home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / AppsToGo / DTS.Lib / TextEditControl.c < prev    next >
Encoding:
Text File  |  1994-03-24  |  80.5 KB  |  3,156 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:         texteditcontrol.c
  5. ** Written by:      Eric Soldan
  6. ** Based on:        TESample, by Bryan Stearns
  7. ** Suggestions by:  Forrest Tanaka, Dave Radcliffe
  8. **
  9. ** Copyright © 1990-1993 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13. /* You may incorporate this sample code into your applications without
  14. ** restriction, though the sample code has been provided "AS IS" and the
  15. ** responsibility for its operation is 100% yours.  However, what you are
  16. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  17. ** after having made changes. If you're going to re-distribute the source,
  18. ** we require that you make it clear in the source that the code was
  19. ** descended from Apple Sample Code, but that you've made changes. */
  20.  
  21. /* This is a control implementation of TextEdit.  The advantages to this are:
  22. **
  23. ** 1) Makes using TextEdit in a non-dialog window easy.
  24. ** 2) The TextEdit record is automatically associated with the window, since
  25. **    it is in the window's control list.
  26. ** 3) The TextEdit control can have scrollbars associated with it, and these
  27. **    are also kept in the window's control list.
  28. ** 4) Updating of the TextEdit record is much simpler, since all that is
  29. **    necessary is to draw the control (or all the window's controls with
  30. **    a DrawControls call).
  31. ** 5) There are simple calls to handle TextEdit events.
  32. ** 6) Undo is already supported.
  33. ** 7) A document length can be specified.  This length will not be exceeded
  34. **    when editing the TextEdit record.
  35. ** 8) When you close the window, the TextEdit record is disposed of.
  36. **    (This automatic disposal can easily be defeated.)
  37. **
  38. **
  39. ** To create a TextEdit control, you only need a single call.  For example:
  40. **
  41. **    CTENew(rViewCtl,            Resource ID of view control for TextEdit control.
  42. **           true,                 Control initially visible.
  43. **           window,                Window to hold TERecord.
  44. **           &teHndl,                Return handle for TERecord.
  45. **           &ctlRct,                Rect for TextEdit view control.
  46. **           &destRct,            destRct for TERecord
  47. **           &viewRct,            viewRct for TERecord
  48. **           &borderRct,            Used to frame a border.
  49. **           32000,                Max size for TERecord text.
  50. **           cteVScrollLessGrow    TERecord read-write, with vertical scroll
  51. **                                that leaves space for grow box.
  52. **    );
  53. **
  54. ** If you create a TextEdit control that is read-only, you will not be able
  55. ** to edit it, of course.  There will also be no blinking caret for that
  56. ** TextEdit control.  You will be able to select text and copy to the
  57. ** clipboard, but that is all.
  58.  
  59. ** Simply create destRct, viewRct, and borderRct appropriately, and
  60. ** then call CTENew (which stands for Control TENew).  If teHndl is returned
  61. ** nil, then CTENew failed.  Otherwise, you now have a TextEdit control in
  62. ** the window.
  63. **
  64. ** NOTE: There is a TextEdit bug (no way!!) such that you may need to set the
  65. **       viewRct right edge 2 bigger than the right edge of destRct.  If you
  66. **       do not do this, then there will be some clipping on the right edge in
  67. **       some cases.  Of course, you may want this.  You may want horizontal
  68. **       scrolling, and therefore you would want the destRct substantially
  69. **       larger than the viewRct.  If you don't want horizontal scrolling,
  70. **       then you probably don't want any clipping horizontally, and therefore
  71. **       you will need to set destRct.right 2 less than viewRct.right.
  72. **
  73. **
  74. ** If the CTENew call succeeds, you then have a TextEdit control in your
  75. ** window.  It will be automatically disposed of when you close the window.
  76. ** If you don't waht this to happen, then you can detach it from the
  77. ** view control which owns it.  To do this, you would to the following:
  78. **
  79. **  viewCtl = CTEViewFromTE(theTextEditHndl);
  80. **  if (viewCtl) SetControlReference(viewCtl, nil);
  81. **
  82. ** The view control keeps a reference to the TextEdit record in the refCon.
  83. ** If the refCon is cleared, then the view control does nothing.  So, all that
  84. ** is needed to detach a TextEdit record from a view control is to set the
  85. ** view control's refCon nil.  Now if you close the window, you will still
  86. ** have the TextEdit record.
  87. **
  88. **
  89. ** To remove a TextEdit control completely from a window, you make one call:
  90. **
  91. **  CTEDispose(theTextEditHndl);
  92. **
  93. ** This disposes of the TextEdit record, the view control, and any scrollbar
  94. ** controls that were created when the TextEdit control was created with
  95. ** the call CTENew.
  96. **
  97. **
  98. ** Events for TextEdit record are handled nearly automatically.  You can
  99. ** make one of 3 calls:
  100. **
  101. **  CTEClick(window, eventPtr, &action);
  102. **  CTEEvent(window, eventPtr, &action);
  103. **  CTEKey(window, eventPtr);
  104. **
  105. ** In each case, if the event was handled, true is returned.  CTEEvent simply
  106. ** calls either CTEClick or CTEKey, whichever is appropriate.
  107. **
  108. **
  109. ** Another call you will want to use is CTEEditMenu.  This is used to set the
  110. ** state of cut/copy/paste/clear for TextEdit controls.  It checks the active
  111. ** control to see if text is selected, if the control is read-only, etc.
  112. ** Based on this information, it sets cut/copy/paste/clear either active
  113. ** or inactive.  If any menu items are set active, it returns true.
  114. **
  115. **
  116. ** One more high-level call is CTEUndo().  In response to an undo menu item
  117. ** being selected by the user, just call CTEUndo(), and the edits the user
  118. ** has made will be undone.  (This includes undoing an undo.)
  119. **
  120. **
  121. ** The last high-level call is CTEClipboard.  Call it when you want to do a
  122. ** cut/copy/paste/clear for the active TextEdit control.  The value to pass
  123. ** is as follows:
  124. **
  125. **  2: cut
  126. **  3: copy
  127. **  4: paste
  128. **  5: clear
  129. **
  130. ** These are the same values you would pass to a DA for these actions.
  131. */
  132.  
  133.  
  134.  
  135. /*****************************************************************************/
  136.  
  137.  
  138.  
  139. #ifndef __TEXTEDITCONTROL__
  140. #include "TextEditControl.h"
  141. #endif
  142.  
  143. #ifndef __BALLOONS__
  144. #include <Balloons.h>
  145. #endif
  146.  
  147. #ifndef __CONTROLS__
  148. #include <Controls.h>
  149. #endif
  150.  
  151. #ifndef __DTSLib__
  152. #include "DTS.Lib.h"
  153. #endif
  154.  
  155. #ifndef __ERRORS__
  156. #include <Errors.h>
  157. #endif
  158.  
  159. #ifndef __EVENTS__
  160. #include <Events.h>
  161. #endif
  162.  
  163. #ifndef __FONTS__
  164. #include <Fonts.h>
  165. #endif
  166.  
  167. #ifndef __GESTALTEQU__
  168. #include <GestaltEqu.h>
  169. #endif
  170.  
  171. #ifndef __MEMORY__
  172. #include <Memory.h>
  173. #endif
  174.  
  175. #ifndef __MENUS__
  176. #include <Menus.h>
  177. #endif
  178.  
  179. #ifndef __OSEVENTS__
  180. #include <OSEvents.h>
  181. #endif
  182.  
  183. #ifndef __OSUTILS__
  184. #include <OSUtils.h>
  185. #endif
  186.  
  187. #ifndef __RESOURCES__
  188. #include <Resources.h>
  189. #endif
  190.  
  191. #ifndef __SCRAP__
  192. #include <Scrap.h>
  193. #endif
  194.  
  195. #ifndef __SCRIPT__
  196. #include <Script.h>
  197. #endif
  198.  
  199. #ifndef __TEXTSERVICES__
  200. #include <TextServices.h>
  201. #endif
  202.  
  203. #ifndef __TSMTE__
  204. #include "TSMTE.h"
  205. #endif
  206.  
  207. #ifndef __UTILITIES__
  208. #include "Utilities.h"
  209. #endif
  210.  
  211.  
  212.  
  213. /*****************************************************************************/
  214.  
  215. #if defined(powerc) || defined (__powerc)
  216. #pragma options align=mac68k
  217. #endif
  218. typedef struct cdefRsrcJMP {
  219.     long    jsrInst;
  220.     long    moveInst;
  221.     short    jmpInst;
  222.     long    jmpAddress;
  223. } cdefRsrcJMP;
  224. typedef cdefRsrcJMP *cdefRsrcJMPPtr, **cdefRsrcJMPHndl;
  225. #if defined(powerc) || defined(__powerc)
  226. #pragma options align=reset
  227. #endif
  228.  
  229.  
  230.  
  231. /*****************************************************************************/
  232.  
  233.  
  234.  
  235. extern Boolean        gInBackground;
  236.  
  237. short    gTECtl    = rTECtl;
  238.  
  239. short    CTEGetLineNum(TEHandle te, short offset);
  240. short    CTEGetLineHeight(TEHandle te, short lineNum, short *ascent);
  241.  
  242. static void                CTEInitialize(void);
  243. static pascal long        CTECtl(short varCode, ControlHandle ctl, short msg, long parm);
  244. static Boolean            GoFast(TEHandle teHndl, EventRecord *event);
  245. static pascal void        TSMTEUpdateProc(TEHandle te, long fixLen, long inputAreaStart,
  246.                                         long inputAreaEnd, long pinStart, long pinEnd, long refCon);
  247.  
  248. static pascal Boolean    PPCClikLoop(TEPtr pTE);
  249. static pascal void        PPCNoCaret(const Rect *r, TEPtr pTE);
  250.  
  251. static cdefRsrcJMPHndl    gCDEF;
  252. static Boolean            gCanGoSlow;
  253. static Boolean            gUseTSMTE;
  254. static WindowPtr        gTEWindow;
  255.  
  256.  
  257.  
  258. /*****************************************************************************/
  259.  
  260.  
  261.  
  262. TEClickLoopUPP    gDefaultClikLoopUPP;
  263.     /* The clikLoop TextEdit wants to use.  Our custom clikLoop must call
  264.     ** this as well.  The default TextEdit clikLoop is stored here. */
  265.  
  266. static ControlDefUPP    gCTECtlUPP;                /* Universal ProcPtr for CTECtl() */
  267. static TEClickLoopUPP    gClikLoopUPP;            /* Universal ProcPtr for our ClikLoop */
  268. static CaretHookUPP        gNoCaretHookUPP;        /* Universal ProcPtr for our CaretHook */
  269.  
  270.  
  271.  
  272. /*****************************************************************************/
  273.  
  274.  
  275.  
  276. static TEHandle            gActiveTEHndl;
  277.     /* Currently active TextEdit record.  (nil if none active.) */
  278.  
  279. static TEHandle            gFoundTEHndl;
  280.     /* Global value used to return info from the TextEdit control proc. */
  281.  
  282. static ControlHandle    gFoundViewCtl;
  283.     /* Global value used to return info from the TextEdit control proc. */
  284.  
  285. static pascal void        VActionProc(ControlHandle scrollCtl, short part);
  286. static pascal void        HActionProc(ControlHandle control, short part);
  287. static void                AdjustOneScrollValue(TEHandle teHndl, ControlHandle ctl, Boolean vert);
  288.  
  289. #define kTELastForWind    1
  290. #define kCrChar            13
  291.  
  292.  
  293.  
  294. static void                dummyCTEActivate(Boolean active, TEHandle teHndl);
  295. static Boolean            dummyCTEClick(WindowPtr window, EventRecord *event, short *action);
  296. static ControlHandle    dummyCTECtlHit(void);
  297. static TEHandle            dummyCTEFindActive(WindowPtr window);
  298. static short            dummyCTEKey(WindowPtr window, EventRecord *event);
  299. static ControlHandle    dummyCTENext(WindowPtr window, TEHandle *teHndl, ControlHandle ctl, short dir, Boolean justActive);
  300. static void                dummyCTESetSelect(short start, short end, TEHandle teHndl);
  301. static ControlHandle    dummyCTEViewFromTE(TEHandle teHndl);
  302. static TEHandle            dummyCTEWindActivate(WindowPtr window, Boolean displayIt);
  303.  
  304. CTEActivateProcPtr           gcteActivate           = dummyCTEActivate;
  305. CTEClickProcPtr              gcteClick              = dummyCTEClick;
  306. CTECtlHitProcPtr             gcteCtlHit             = dummyCTECtlHit;
  307. CTEFindActiveProcPtr         gcteFindActive         = dummyCTEFindActive;
  308. CTEKeyProcPtr                gcteKey                = dummyCTEKey;
  309. CTENextProcPtr               gcteNext               = dummyCTENext;
  310. CTESetSelectProcPtr          gcteSetSelect          = dummyCTESetSelect;
  311. CTEViewFromTEProcPtr         gcteViewFromTE         = dummyCTEViewFromTE;
  312. CTEWindActivateProcPtr       gcteWindActivate       = dummyCTEWindActivate;
  313.  
  314.  
  315.  
  316. /*****************************************************************************/
  317. /*****************************************************************************/
  318. /*****************************************************************************/
  319.  
  320.  
  321.  
  322. /* Instead of calling the functions directly, you can reference the global
  323. ** proc pointers that reference the functions.  This keeps everything from
  324. ** being linked in.  The default global proc pointers point to dummy functions
  325. ** that behave as if there aren't any TextEdit controls.  The calls can still be
  326. ** made, yet the runtime behavior is such that it will operate as if there
  327. ** no instances of the TextEdit control.  This allows intermediate code to access
  328. ** the functions or not without automatically linking in all sorts of stuff
  329. ** into the application that isn't desired.  To change the global proc pointers
  330. ** so that they point to the actual functions, just call CTEInitialize() once
  331. ** in the beginning of the application.  If CTEInitialize() is referenced, it will
  332. ** get linked in.  In turn, everything that it references directly or indirectly
  333. ** will get linked in. */
  334.  
  335. #pragma segment TextEditControl
  336. static void    CTEInitialize(void)
  337. {
  338.     if (gcteActivate != CTEActivate) {
  339.         gcteActivate           = CTEActivate;
  340.         gcteClick              = CTEClick;
  341.         gcteCtlHit             = CTECtlHit;
  342.         gcteFindActive         = CTEFindActive;
  343.         gcteKey                = CTEKey;
  344.         gcteNext               = CTENext;
  345.         gcteSetSelect          = CTESetSelect;
  346.         gcteViewFromTE         = CTEViewFromTE;
  347.         gcteWindActivate       = CTEWindActivate;
  348.  
  349.         CTEConvertClipboard(true, true);
  350.     }
  351. }
  352.  
  353.  
  354.  
  355. /*****************************************************************************/
  356.  
  357.  
  358.  
  359. /* Activate this TextEdit record.  If another is currently active, deactivate
  360. ** that one.  The view control for this TextEdit record is also flagged to
  361. ** indicate which was the last active one for this window.  If the previous
  362. ** active TextEdit record was in the same window, then flag the old one off
  363. ** for this window.  The whole point for this per-window flagging is so that
  364. ** activate events can reactivate the correct TextEdit control per window. */
  365.  
  366. #pragma segment TextEditControl
  367. void    CTEActivate(Boolean active, TEHandle teHndl)
  368. {
  369.     WindowPtr        tePort, oldPort;
  370.     ControlHandle    viewCtl;
  371.     TEHandle        te;
  372.     CTEDataHndl        teData;
  373.     short            oldDisplay, newDisplay;
  374.  
  375.     if (!teHndl) return;
  376.  
  377.     teData = nil;
  378.     viewCtl = CTEViewFromTE(teHndl);
  379.     if (viewCtl)
  380.         teData = (CTEDataHndl)(*viewCtl)->contrlData;
  381.  
  382.     if (!active) {
  383.         GetPort(&oldPort);
  384.         SetPort(tePort = (*teHndl)->inPort);
  385.         if(gUseTSMTE)
  386.             DeactivateTSMDocument((*teData)->docID);
  387.         TEDeactivate(teHndl);
  388.         if (teHndl == gActiveTEHndl)
  389.             gActiveTEHndl = nil;
  390.         if (viewCtl)
  391.             CTEUpdate(teHndl, viewCtl, true);
  392.         SetPort(oldPort);
  393.         return;
  394.     }
  395.  
  396.     if (!viewCtl)               return;
  397.     if (!(*viewCtl)->contrlVis) return;
  398.  
  399.     (*teData)->mode |= cteActive;
  400.     GetPort(&oldPort);
  401.     SetPort(tePort = (*teHndl)->inPort);
  402.  
  403.     if (!gInBackground) {
  404.         if(gUseTSMTE)
  405.             ActivateTSMDocument((*teData)->docID);
  406.         TEActivate(gActiveTEHndl = teHndl);
  407.     }
  408.  
  409.     CTEUpdate(teHndl, viewCtl, true);
  410.     SetPort(oldPort);
  411.         /* Let TextEdit know that it is supposed to be active. */
  412.  
  413.     for (viewCtl = nil;;) {
  414.         viewCtl = CTENext(tePort, &te, viewCtl, 1, false);
  415.         if (!viewCtl) break;
  416.         if (te != teHndl) {
  417.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  418.             oldDisplay = (*teData)->mode;
  419.             newDisplay = (oldDisplay & (0xFFFF - cteActive));
  420.             if (oldDisplay != newDisplay) {
  421.                 (*teData)->mode = newDisplay;
  422.                 CTEActivate(false, te);
  423.             }
  424.         }
  425.     }
  426. }
  427.  
  428.  
  429.  
  430. static void    dummyCTEActivate(Boolean active, TEHandle teHndl)
  431. {
  432. #ifndef __MWERKS__
  433. #pragma unused (active, teHndl)
  434. #endif
  435. }
  436.  
  437.  
  438.  
  439. /*****************************************************************************/
  440.  
  441.  
  442.  
  443. /* This is called when a mouseDown occurs in the content of a window.  It
  444. ** returns true if the mouseDown caused a TextEdit action to occur.  Events
  445. ** that are handled include if the user clicks on a scrollbar that is
  446. ** associated with a TextEdit control. */
  447.  
  448. #pragma segment TextEditControl
  449. Boolean    CTEClick(WindowPtr window, EventRecord *event, short *action)
  450. {
  451.     WindowPtr        oldPort;
  452.     Point            mouseLoc;
  453.     TEHandle        te, teActive;
  454.     ControlHandle    ctlHit, viewCtl;
  455.     CTEDataHndl        teData;
  456.     Boolean            vert;
  457.     short            extendSelect, part, value, newValue, lh, mode;
  458.  
  459.     static ControlActionUPP    hcupp, vcupp;
  460.  
  461.     if (action)
  462.         *action = 0;
  463.  
  464.     GetPort(&oldPort);
  465.     if (!((WindowPeek)window)->hilited) return(false);
  466.  
  467.     SetPort(window);
  468.     mouseLoc = event->where;
  469.     GlobalToLocal(&mouseLoc);
  470.  
  471.     if (!(viewCtl = CTEFindCtl(window, event, &te, &ctlHit))) return(false);
  472.  
  473.     if (viewCtl == ctlHit) {
  474.             /* See if the user clicked directly on the view control for a
  475.             ** TextEdit record.  If so, we definitely have some work to do. */
  476.         if ((*viewCtl)->contrlHilite != 255) {
  477.             if (te != gActiveTEHndl) {
  478.                 CTEActivate(true, te);
  479.                 if (action)
  480.                     *action = -1;
  481.                 SetPort(oldPort);
  482.                 return(true);
  483.                     /* If user clicked on TextEdit control other than the
  484.                     ** currently active control, then activate it.  This is our
  485.                     ** only action in this case. */
  486.             }
  487.             extendSelect = ((event->modifiers & shiftKey) != 0);
  488.                 /* Extend-select may be occuring. */
  489.  
  490.             gCanGoSlow = true;
  491.                 /* There is a slow-zone around the TextEdit area for slow extend-select.
  492.                 ** Allow this zone to slow down selection. */
  493.  
  494.                 if (gUseTSMTE) {
  495.                     if (!TSMEvent(event))
  496.                         TEClick(mouseLoc, extendSelect, te);
  497.                 }
  498.                 else TEClick(mouseLoc, extendSelect, te);
  499.                     /* Do the extend-select thing.  Most of the work is handled by
  500.                     ** TextEdit.  The only thing we have to do is to update the
  501.                     ** scrollbars while the user is extending the select.  This is
  502.                     ** taken care of by our custom clikLoop procedure. */
  503.  
  504.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  505.             (*teData)->newUndo = true;
  506.  
  507.             SetPort(oldPort);
  508.             return(true);
  509.         }
  510.     }
  511.  
  512. /* We didn't hit the view control for a TextEdit record, but don't give up yet.
  513. ** The user may be clicking on a related scrollbar.  Let's find out... */
  514.  
  515.     if (WhichControl(mouseLoc, event->when, window, &ctlHit)) {
  516.             /* The user did click on a control.  But is it a scrollbar
  517.             ** for a TextEdit control?  Stay tuned... */
  518.  
  519.         te = CTEFromScroll(ctlHit, &viewCtl);
  520.  
  521.         if (te) {        /* It was a related scrollbar. */
  522.  
  523.             if ((*viewCtl)->contrlHilite != 255) {
  524.                 if (te != gActiveTEHndl) {
  525.                     CTEActivate(true, te);
  526.                     if (action)
  527.                         *action = -1;
  528.                     SetPort(oldPort);
  529.                     return(true);
  530.                         /* If user clicked on TextEdit control other than the
  531.                         ** currently active control, then activate it.  This is our
  532.                         ** only action in this case. */
  533.                 }
  534.             }
  535.  
  536.             vert = ((*ctlHit)->contrlRect.top <= (*viewCtl)->contrlRect.top);
  537.                 /* Horizontal or vertical scroll.  Only the rect knows. */
  538.  
  539.             part = FindControl(mouseLoc, window, &ctlHit);
  540.  
  541.             switch (part) {
  542.                 case 0:        /* Inactive scrollbar. */
  543.                     break;
  544.                 case inThumb:
  545.                     value = GetControlValue(ctlHit);
  546.                     part  = TrackControl(ctlHit, mouseLoc, nil);
  547.                     if (part) {
  548.                         newValue = GetControlValue(ctlHit);
  549.                         if (value != newValue) {    /* If scrollbar value changed... */
  550.                             if (vert) {
  551.                                 teData = (CTEDataHndl)(*viewCtl)->contrlData;
  552.                                 mode   = (*teData)->mode;
  553.                                 if (mode & cteScrollFullLines) {
  554.                                     if (!(mode & cteStyledTE)) {
  555.                                         lh = CTEGetLineHeight(te, 1, nil);
  556.                                         if (lh) {
  557.                                             newValue += (lh >> 1);
  558.                                             newValue /= lh;
  559.                                             newValue *= lh;
  560.                                             SetControlValue(ctlHit, newValue);
  561.                                         }
  562.                                     }
  563.                                 }
  564.                                 TEScroll(0, value - newValue, te);
  565.                             }
  566.                             else
  567.                                 TEScroll(value - newValue, 0, te);
  568.                         }
  569.                     }
  570.                     break;
  571.  
  572.                 default:
  573.                     teActive = gActiveTEHndl;
  574.                     gActiveTEHndl = te;
  575.                         /* This is a hack way to pass the action procedure
  576.                         ** which TextEdit record we are dealing with. */
  577.  
  578.                     if (vert) {
  579.                         if (!vcupp) vcupp = NewControlActionProc(VActionProc);
  580.                         TrackControl(ctlHit, mouseLoc, vcupp);
  581.                     }
  582.                     else {
  583.                         if (!hcupp) hcupp = NewControlActionProc(HActionProc);
  584.                         TrackControl(ctlHit, mouseLoc, hcupp);
  585.                     }
  586.  
  587.                     gActiveTEHndl = teActive;
  588.                         /* Unhack our previous hack. */
  589.                     break;
  590.             }
  591.  
  592.             SetPort(oldPort);
  593.             return(true);
  594.         }
  595.     }
  596.  
  597.     SetPort(oldPort);
  598.     return(false);
  599. }
  600.  
  601.  
  602.  
  603. static Boolean    dummyCTEClick(WindowPtr window, EventRecord *event, short *action)
  604. {
  605. #ifndef __MWERKS__
  606. #pragma unused (window, event)
  607. #endif
  608.  
  609.     if (action)
  610.         *action = 0;
  611.     return(false);
  612. }
  613.  
  614.  
  615.  
  616. /*****************************************************************************/
  617.  
  618.  
  619.  
  620. /* This is the custom clikLoop, which is called from the assembly glue code.
  621. ** This handles updating the scrollbars as the user is drag-selecting in
  622. ** the TextEdit control. */
  623.  
  624. #pragma segment TextEditControl
  625. void    CTEClikLoop(void)
  626. {
  627.     WindowPtr        oldPort, window;
  628.     TEHandle        te;
  629.     Point            mouseLoc;
  630.     Rect            viewRct;
  631.     RgnHandle        rgn;
  632.     short            dl, dr, dt, db;
  633.     long            tick;
  634.  
  635.     GetPort(&oldPort);
  636.     SetPort(window = (WindowPtr)(*gActiveTEHndl)->inPort);
  637.  
  638.     te = gActiveTEHndl;
  639.         /* This better be what the user is dragging, or we did something
  640.         ** wrong elsewhere.
  641.         */
  642.  
  643.     GetMouse(&mouseLoc);
  644.     viewRct = (*te)->viewRect;
  645.  
  646.     if (!PtInRect(mouseLoc, &viewRct)) {
  647.         /* User is outside the TextEdit area, so scrolling is happening. */
  648.  
  649.         tick = gCanGoSlow;
  650.         if (tick)
  651.             tick = TickCount();
  652.                 /* As an extra feature, there is a zone around the TextEdit
  653.                 ** viewRct that the scroll will be slowed down.  If the user
  654.                 ** drags outside the viewRct outside this zone, then scrolling
  655.                 ** occurs as fast as possible. */
  656.  
  657.         rgn = NewRgn();
  658.         GetClip(rgn);
  659.         ClipRect(&(window->portRect));
  660.             /* The clipRgn is set to protect everything outside viewRct.
  661.             ** This doesn't work very well when we want to change
  662.             ** the scrollbars.  Save the old and open it up.
  663.             */
  664.  
  665.         dl = viewRct.left - mouseLoc.h;
  666.         dr = mouseLoc.h   - viewRct.right;
  667.         dt = viewRct.top  - mouseLoc.v;
  668.         db = mouseLoc.v   - viewRct.bottom;
  669.             /* Check the delta value for each side of viewRct.  This will
  670.             ** be used to determine if we should scroll fast or slow.
  671.             */
  672.  
  673.         CTEAdjustScrollValues(te);
  674.             /* Scroll them puppies. */
  675.  
  676.         SetClip(rgn);                                /* restore clip */
  677.         DisposeRgn(rgn);
  678.             /* Make Mr. clipRgn happy again. */
  679.  
  680.         if ((dl < 16) && (dr < 16) && (dt < 16) && (db < 16))
  681.             while (tick + 10 > TickCount()) {};
  682.                 /* Do it really slow.  (This is important on very fast machines.) */
  683.     }
  684.  
  685.     SetPort(oldPort);
  686. }
  687.  
  688.  
  689.  
  690. /*****************************************************************************/
  691.  
  692.  
  693.  
  694. /* Do the cut/copy/paste/clear operations for the currently active
  695. ** TextEdit control.  Caller assumes appropriateness of the call.  Typically,
  696. ** this routine won't be called at an inappropriate time, since the menu
  697. ** item should be enabled or disabled correctly.
  698. ** Use CTEEditMenu to set the menu items undo/cut/copy/paste/clear correctly
  699. ** for the active TextEdit control.  Since undo isn't currently supported,
  700. ** all that CTEEditMenu does for the undo case is to deactivate it right now. */
  701.  
  702. #pragma segment TextEditControl
  703. ControlHandle    CTEClipboard(short menuID)
  704. {
  705.     WindowPtr        oldPort;
  706.     TEHandle        te;
  707.     ControlHandle    viewCtl;
  708.     CTEDataHndl        teData;
  709.     long            maxTextLen, charsToAdd;
  710.  
  711.     if (!(te = gActiveTEHndl))          return(nil);
  712.     if (!(viewCtl = CTEViewFromTE(te))) return(nil);
  713.  
  714.     GetPort(&oldPort);
  715.     SetPort((*te)->inPort);
  716.     switch (menuID) {
  717.         case 2:
  718.             CTENewUndo(viewCtl, true);
  719.             TECut(te);
  720.             break;
  721.         case 3:
  722.             TECopy(te);
  723.             viewCtl = nil;
  724.             break;
  725.         case 4:
  726.             if (viewCtl) {
  727.                 teData = (CTEDataHndl)(*viewCtl)->contrlData;
  728.                 maxTextLen  = (*teData)->maxTextLen;
  729.                 charsToAdd  = TEGetScrapLength();
  730.                 charsToAdd -= ((*te)->selEnd - (*te)->selStart);
  731.                 if ((*te)->teLength + charsToAdd <= maxTextLen) {
  732.                     CTENewUndo(viewCtl, true);
  733.                     if ((*teData)->mode & cteStyledTE)
  734.                         TEStylePaste(te);
  735.                     else
  736.                         TEPaste(te);
  737.                 }
  738.                 else viewCtl = nil;
  739.             }
  740.             break;
  741.         case 5:
  742.             CTENewUndo(viewCtl, true);
  743.             TEDelete(te);
  744.             break;
  745.     }
  746.  
  747.     CTEAdjustTEBottom(te);
  748.     CTEAdjustScrollValues(te);
  749.     SetPort(oldPort);
  750.  
  751.     return(viewCtl);
  752. }
  753.  
  754.  
  755.  
  756. /*****************************************************************************/
  757.  
  758.  
  759.  
  760. #pragma segment TextEditControl
  761. void    CTEConvertClipboard(Boolean convertClipboard, Boolean becomingActive)
  762. {
  763. #ifndef __MWERKS__
  764. #pragma unused (convertClipboard, becomingActive)
  765. #endif
  766. }
  767.  
  768.  
  769.  
  770. /*****************************************************************************/
  771.  
  772.  
  773.  
  774. #pragma segment TextEditControl
  775. static pascal long    CTECtl(short varCode, ControlHandle ctl, short msg, long parm)
  776. {
  777. #ifndef __MWERKS__
  778. #pragma unused (varCode)
  779. #endif
  780.  
  781.     Rect            viewRct;
  782.     TEHandle        te;
  783.     CTEDataHndl        teData;
  784.     ControlHandle    scrollCtl;
  785.     short            i;
  786.  
  787.     te = (TEHandle)GetControlReference(ctl);
  788.     if (te)
  789.         viewRct = (*ctl)->contrlRect;
  790.     else
  791.         SetRect(&viewRct, 0, 0, 0, 0);
  792.  
  793.     switch (msg) {
  794.         case drawCntl:
  795.             CTEUpdate(te, ctl, false);
  796.             break;
  797.  
  798.         case testCntl:
  799.             if (PtInRect(*(Point *)&parm, &viewRct)) {
  800.                 gFoundViewCtl = ctl;
  801.                 gFoundTEHndl  = te;
  802.                 return(1);
  803.             }
  804.             return(0);
  805.             break;
  806.  
  807.         case calcCRgns:
  808.         case calcCntlRgn:
  809.             if (msg == calcCRgns)
  810.                 parm &= 0x00FFFFFF;
  811.             RectRgn((RgnHandle)parm, &viewRct);
  812.             break;
  813.  
  814.         case initCntl:
  815.             break;
  816.  
  817.         case dispCntl:
  818.             if (te) {
  819.                 if (te == gActiveTEHndl)
  820.                     gActiveTEHndl = nil;
  821.                 TEDispose(te);
  822.                 teData = (CTEDataHndl)(*ctl)->contrlData;
  823.                 if (teData) {
  824.                     if ((*teData)->undoText)
  825.                         DisposeHandle((Handle)(*teData)->undoText);
  826.                     if ((*teData)->undoStyl)
  827.                         DisposeHandle((Handle)(*teData)->undoStyl);
  828.                     if ((*teData)->docID)
  829.                         DeleteTSMDocument((*teData)->docID);
  830.                     DisposeHandle((Handle)teData);
  831.                 }
  832.                 for (i = 0; i < 2; ++i) {
  833.                     scrollCtl = CTEScrollFromView(ctl, i);
  834.                     if (scrollCtl)
  835.                         DisposeControl(scrollCtl);
  836.                 }
  837.             }
  838.             break;
  839.  
  840.         case posCntl:
  841.             break;
  842.  
  843.         case thumbCntl:
  844.             break;
  845.  
  846.         case dragCntl:
  847.             break;
  848.  
  849.         case autoTrack:
  850.             break;
  851.     }
  852.  
  853.     return(0);
  854. }
  855.  
  856.  
  857.  
  858. /*****************************************************************************/
  859.  
  860.  
  861.  
  862. /* The TextEdit control that was hit by calling FindControl is saved in a
  863. ** global variable, since the CDEF has no way of returning what kind it was.
  864. ** To determine that it was a TextEdit control that was hit, first call this
  865. ** function.  The first call returns the old value in the global variable,
  866. ** plus it resets the global to nil.  Then call FindControl(), and then
  867. ** call this function again.  If it returns nil, then a TextEdit control
  868. ** wasn't hit.  If it returns non-nil, then it was a TextEdit control that
  869. ** was hit, and specifically the one returned. */
  870.  
  871. #pragma segment TextEditControl
  872. ControlHandle    CTECtlHit(void)
  873. {
  874.     ControlHandle    ctl;
  875.  
  876.     ctl = gFoundViewCtl;
  877.     gFoundViewCtl = nil;
  878.     return(ctl);
  879. }
  880.  
  881.  
  882.  
  883. static ControlHandle    dummyCTECtlHit(void)
  884. {
  885.     return(nil);
  886. }
  887.  
  888.  
  889.  
  890. /*****************************************************************************/
  891.  
  892.  
  893.  
  894. /* Disposes of the TERecord, TextEdit control, and any related scrollbars. */
  895.  
  896. #pragma segment TextEditControl
  897. void    CTEDispose(TEHandle teHndl)
  898. {
  899.     WindowPtr    oldPort;
  900.  
  901.     if (teHndl) {
  902.         GetPort(&oldPort);
  903.         SetPort((*teHndl)->inPort);
  904.         TEDispose(CTEDisposeView(CTEViewFromTE(teHndl)));
  905.             /* Dispose of the TextEdit control completely.  This includes
  906.             ** scrollbars, as well as the TextEdit view control.
  907.             */
  908.         SetPort(oldPort);
  909.     }
  910. }
  911.  
  912.  
  913.  
  914. /*****************************************************************************/
  915.  
  916.  
  917.  
  918. /* Dispose of the view control and related scrollbars.  This function also
  919. ** returns the handle to the TextEdit record, since it was just orphaned.
  920. ** Use this function if you want to get rid of a TextEdit control, but you
  921. ** want to keep the TextEdit record. */
  922.  
  923. #pragma segment TextEditControl
  924. TEHandle    CTEDisposeView(ControlHandle viewCtl)
  925. {
  926.     TEHandle        te;
  927.     short            vert;
  928.     ControlHandle    ctl;
  929.  
  930.     if (!viewCtl) return(nil);
  931.  
  932.     te = (TEHandle)GetControlReference(viewCtl);
  933.     SetControlReference(viewCtl, (long)nil);
  934.  
  935.     for (vert = 0; vert < 2; ++vert) {
  936.         ctl = CTEScrollFromView(viewCtl, vert);
  937.         if (ctl)
  938.             DisposeControl(ctl);
  939.     }
  940.  
  941.     DisposeControl(viewCtl);
  942.     return(te);
  943. }
  944.  
  945.  
  946.  
  947. /*****************************************************************************/
  948.  
  949.  
  950.  
  951. /* Returns the full document height. */
  952.  
  953. #pragma segment TextEditControl
  954. short    CTEDocHeight(TEHandle teHndl)
  955. {
  956.     short        h, lh, a;
  957.     TextStyle    st;
  958.  
  959.     if (!teHndl) return(0);
  960.  
  961.     h = TEGetHeight((*teHndl)->nLines, 1, teHndl);
  962.         /* Get the whole doc height. */
  963.  
  964.     if ((*teHndl)->nLines != CTENumTextLines(teHndl)) {        /* If # of lines is wrong by one... */
  965.         TEGetStyle((*teHndl)->teLength, &st, &lh, &a, teHndl);
  966.         h += lh;                                            /* Add in height of last line. */
  967.     }
  968.  
  969.     return(h);
  970. }
  971.  
  972.  
  973.  
  974. /*****************************************************************************/
  975.  
  976.  
  977.  
  978. /* Enable or disable edit menu items based on the active TextEdit control.
  979. ** You pass the menu ID of the undo item in undoID, and the menu ID of the
  980. ** cut item in cutID.  If undoID or cutID is non-zero, then some action is
  981. ** performed.  If you pass a non-zero value for cutID, then the other menu
  982. ** items cut/copy/paste/clear are updated to reflect the status of the
  983. ** active TextEdit control. */
  984.  
  985. #pragma segment TextEditControl
  986. Boolean    CTEEditMenu(Boolean *activeItem, short editMenu, short undoID, short cutID)
  987. {
  988.     TEHandle        te;
  989.     MenuHandle        menu;
  990.     Boolean            active;
  991.     ControlHandle    viewCtl;
  992.     CTEDataHndl        teData;
  993.     long            dataLen, scrapOffset;
  994.  
  995.     active = false;
  996.     if (activeItem) *activeItem = false;
  997.     menu = GetMenuHandle(editMenu);
  998.  
  999.     if (undoID)
  1000.         DisableItem(menu, undoID);
  1001.  
  1002.     if (cutID) {
  1003.         DisableItem(menu, cutID);            /* Disable cut. */
  1004.         DisableItem(menu, cutID + 1);        /* Disable copy. */
  1005.         DisableItem(menu, cutID + 2);        /* Disable paste. */
  1006.         DisableItem(menu, cutID + 3);        /* Disable clear. */
  1007.     }
  1008.  
  1009.     if (!(te = gActiveTEHndl)) return(false);
  1010.  
  1011.     if (undoID) {
  1012.         viewCtl = CTEViewFromTE(te);
  1013.         if (viewCtl) {
  1014.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  1015.             if ((*teData)->undoText) {
  1016.                 EnableItem(menu, undoID);
  1017.                 active = true;
  1018.             }
  1019.         }
  1020.     }
  1021.  
  1022.     if (cutID) {
  1023.         if ((*te)->selStart != (*te)->selEnd) {
  1024.             if (!CTEReadOnly(te)) {
  1025.                 EnableItem(menu, cutID);        /* Enable cut. */
  1026.                 EnableItem(menu, cutID + 3);    /* Enable clear. */
  1027.             }
  1028.             active = true;
  1029.             EnableItem(menu, cutID + 1);        /* Enable copy. */
  1030.         }
  1031.         if (!CTEReadOnly(te)) {
  1032.             dataLen = GetScrap(nil, 'TEXT', &scrapOffset);
  1033.             if (dataLen > 0) {
  1034.                 active = true;
  1035.                 EnableItem(menu, cutID + 2);        /* Enable paste. */
  1036.             }
  1037.         }
  1038.     }
  1039.  
  1040.     if (activeItem)
  1041.         *activeItem = active;
  1042.  
  1043.     return(true);
  1044. }
  1045.  
  1046.  
  1047.  
  1048. /*****************************************************************************/
  1049.  
  1050.  
  1051.  
  1052. /* Handle the event if it applies to the active TextEdit control.  If some
  1053. ** action occured due to the event, return true. */
  1054.  
  1055. #pragma segment TextEditControl
  1056. Boolean    CTEEvent(WindowPtr window, EventRecord *event, short *action)
  1057. {
  1058.     WindowPtr    clickWindow;
  1059.     short        actn;
  1060.  
  1061.     if (action)
  1062.         *action = 0;
  1063.  
  1064.     switch(event->what) {
  1065.  
  1066.         case mouseDown:
  1067.             if (FindWindow(event->where, &clickWindow) == inContent)
  1068.                 if (window == clickWindow)
  1069.                     if (((WindowPeek)window)->hilited) return(CTEClick(window, event, action));
  1070.             break;
  1071.  
  1072.         case autoKey:
  1073.         case keyDown:
  1074.             if (!(event->modifiers & cmdKey)) {
  1075.                 actn = CTEKey(window, event);
  1076.                 if (action)
  1077.                     *action = actn;
  1078.                 if (actn) return(true);
  1079.             }
  1080.             break;
  1081.     }
  1082.  
  1083.     return(false);
  1084. }
  1085.  
  1086.  
  1087.  
  1088. /*****************************************************************************/
  1089.  
  1090.  
  1091.  
  1092. /* Returns the active TextEdit control, if any.  If nil is passed in, then
  1093. ** the return value represents whatever TextEdit control is active, independent
  1094. ** of what window it is in.  If a window is passed in, then it returns a
  1095. ** TextEdit control only if the active control is in the specified window.
  1096. ** If the active TextEdit control is in some other window, then nil is returned. */
  1097.  
  1098. #pragma segment TextEditControl
  1099. TEHandle    CTEFindActive(WindowPtr window)
  1100. {
  1101.     if (!window) return(gActiveTEHndl);
  1102.         /* User wants whatever is active one, for whatever window. */
  1103.  
  1104.     if (!gActiveTEHndl) return(nil);
  1105.     if (window != (*gActiveTEHndl)->inPort) return(nil);
  1106.     return(gActiveTEHndl);
  1107. }
  1108.  
  1109.  
  1110.  
  1111. static TEHandle    dummyCTEFindActive(WindowPtr window)
  1112. {
  1113. #ifndef __MWERKS__
  1114. #pragma unused (window)
  1115. #endif
  1116.     return(nil);
  1117. }
  1118.  
  1119.  
  1120.  
  1121. /*****************************************************************************/
  1122.  
  1123.  
  1124.  
  1125. /* This determines if a TextEdit control was clicked on directly.  This does
  1126. ** not determine if a related scrollbar was clicked on.  If a TextEdit
  1127. ** control was clicked on, then true is returned, as well as the TextEdit
  1128. ** handle and the handle to the view control. */
  1129.  
  1130. #pragma segment TextEditControl
  1131. ControlHandle    CTEFindCtl(WindowPtr window, EventRecord *event, TEHandle *teHndl, ControlHandle *ctlHit)
  1132. {
  1133.     WindowPtr        oldPort;
  1134.     Point            mouseLoc;
  1135.     ControlHandle    ctl, tectl;
  1136.     TEHandle        te;
  1137.  
  1138.     if (ctlHit) *ctlHit = nil;
  1139.     if (teHndl) *teHndl = nil;
  1140.  
  1141.     gFoundTEHndl = nil;
  1142.  
  1143.     if (window) {
  1144.         GetPort(&oldPort);
  1145.         SetPort(window);
  1146.         mouseLoc = event->where;
  1147.         GlobalToLocal(&mouseLoc);
  1148.         SetPort(oldPort);
  1149.  
  1150.         if (!WhichControl(mouseLoc, 0, window, &ctl)) return(nil);
  1151.             /* Didn't hit a thing, so forget it. */
  1152.  
  1153.         te = CTEFromScroll(ctl, &tectl);
  1154.         if (te) {
  1155.             if (ctlHit)
  1156.                 *ctlHit = ctl;
  1157.             if (teHndl)
  1158.                 *teHndl = te;
  1159.             return(tectl);
  1160.         }
  1161.  
  1162.         FindControl(mouseLoc, window, &ctl);
  1163.         if (!ctl)                                     return(nil);
  1164.         if (*(*ctl)->contrlDefProc != *(Handle)gCDEF) return(nil);
  1165.             /* Control hit was above TE control, so we didn't hit a TE control. */
  1166.         if (ctlHit)
  1167.             *ctlHit = ctl;
  1168.         if (teHndl)
  1169.             *teHndl = gFoundTEHndl;
  1170.         if (gFoundTEHndl) return(ctl);
  1171.     }
  1172.  
  1173.     return(nil);
  1174. }
  1175.  
  1176.  
  1177.  
  1178. /*****************************************************************************/
  1179.  
  1180.  
  1181.  
  1182. /* Find the TextEdit record that is related to the indicated scrollbar. */
  1183.  
  1184. #pragma segment TextEditControl
  1185. TEHandle    CTEFromScroll(ControlHandle scrollCtl, ControlHandle *retCtl)
  1186. {
  1187.     WindowPtr        window;
  1188.     ControlHandle    viewCtl;
  1189.     TEHandle        te;
  1190.  
  1191.     if (!IsScrollBar(scrollCtl)) {
  1192.         if (retCtl) *retCtl = nil;
  1193.         return(nil);
  1194.     }
  1195.  
  1196.     window = (*scrollCtl)->contrlOwner;
  1197.  
  1198.     for (viewCtl = nil;;) {
  1199.         viewCtl = CTENext(window, &te, viewCtl, 1, false);
  1200.         if (!viewCtl) return(nil);
  1201.         if (viewCtl == (ControlHandle)GetControlReference(scrollCtl)) {
  1202.             if (retCtl) *retCtl = viewCtl;
  1203.             return(te);
  1204.         }
  1205.     }
  1206. }
  1207.  
  1208.  
  1209.  
  1210. /*****************************************************************************/
  1211.  
  1212.  
  1213.  
  1214. /* Hide the designated TextEdit control and related scrollbars. */
  1215.  
  1216. #pragma segment TextEditControl
  1217. Rect    CTEHide(TEHandle teHndl)
  1218. {
  1219.     ControlHandle    viewCtl, scrollCtl;
  1220.     short            i, mode;
  1221.     CTEDataHndl        teData;
  1222.     Rect            viewRct, brdrRct;
  1223.  
  1224.     SetRect(&brdrRct, 0, 0, 0, 0);
  1225.  
  1226.     if (teHndl) {
  1227.         CTEActivate(false, teHndl);
  1228.         viewCtl = CTEViewFromTE(teHndl);
  1229.         if (viewCtl) {
  1230.             HideControl(viewCtl);
  1231.             for (i = 0; i < 2; i++) {
  1232.                 scrollCtl = CTEScrollFromView(viewCtl, i);
  1233.                 if (scrollCtl)
  1234.                     HideControl(scrollCtl);
  1235.             }
  1236.  
  1237.             teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  1238.             mode    = (*teData)->mode;
  1239.             viewRct = (*teHndl)->viewRect;
  1240.             brdrRct = (*teData)->brdrRect;
  1241.         
  1242.             if (EmptyRect(&brdrRct)) brdrRct = viewRct;
  1243.  
  1244.             if (mode & cteVScroll) brdrRct.right  += 15;
  1245.             if (mode & cteHScroll) brdrRct.bottom += 15;
  1246.  
  1247.             if (mode & cteShowActive) InsetRect(&brdrRct, -3, -3);
  1248.         }
  1249.     }
  1250.  
  1251.     return(brdrRct);
  1252. }
  1253.  
  1254.  
  1255.  
  1256. /*****************************************************************************/
  1257.  
  1258.  
  1259.  
  1260. /* Blink the caret in the active TextEdit control.  The active TextEdit
  1261. ** control may be read-only, in which case the caret does not blink. */
  1262.  
  1263. #pragma segment TextEditControl
  1264. void    CTEIdle(void)
  1265. {
  1266.     WindowPtr        window;
  1267.     ControlHandle    viewCtl;
  1268.     Rect            rct;
  1269.  
  1270.     if (gActiveTEHndl) {
  1271.         if (!(viewCtl = CTEViewFromTE(gActiveTEHndl))) return;
  1272.         if (!((*viewCtl)->contrlVis))                  return;
  1273.         if ((*viewCtl)->contrlHilite == 255)           return;
  1274.         window = (*gActiveTEHndl)->inPort;
  1275.         if (((WindowPeek)window)->hilited) {
  1276.             if (GetWRefCon(window)) {
  1277.                 rct = (*(((WindowPeek)window)->updateRgn))->rgnBBox;
  1278.                 if (EmptyRect(&rct))
  1279.                     TEIdle(gActiveTEHndl);
  1280.             }
  1281.         }
  1282.     }
  1283. }
  1284.  
  1285.  
  1286.  
  1287. /*****************************************************************************/
  1288.  
  1289.  
  1290.  
  1291. /* See if the keypress event applies to the TextEdit control, and if it does,
  1292. ** handle it and return non-zero.  If the key caused a change in the TERecord,
  1293. ** return 2.  If the key was handled with no change to the TERecord, return 1. */
  1294.  
  1295. #pragma segment TextEditControl
  1296. short    CTEKey(WindowPtr window, EventRecord *event)
  1297. {
  1298.     TEHandle            te;
  1299.     ControlHandle        viewCtl;
  1300.     short                maxTextLen, selStart, selEnd;
  1301.     short                textSelected, arrowKey, retval;
  1302.     char                key;
  1303.     CTEDataHndl            teData;
  1304.     CTEKeyFilterProcPtr    kproc;
  1305.     CTEFastKeysProcPtr    fproc;
  1306.     short                handled;
  1307.     Boolean                looping, refig, tsmHandled;
  1308.     EventRecord            lclEvent;
  1309.  
  1310.     if (!(te = gActiveTEHndl))                return(0);
  1311.     if ((*gActiveTEHndl)->inPort != window) return(0);
  1312.     if (CTEReadOnly(te))                    return(0);
  1313.     if (!(viewCtl = CTEViewFromTE(te)))        return(0);
  1314.     if ((*viewCtl)->contrlHilite == 255)    return(0);
  1315.  
  1316.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  1317.     handled = 0;
  1318.     kproc = (*teData)->keyFilter;
  1319.     if (kproc)
  1320.         if ((*kproc)(te, event, &handled))
  1321.             return(handled);
  1322.  
  1323.     retval = 1;
  1324.  
  1325.     for (refig = looping = false;; looping = true) {
  1326.  
  1327.         if (looping) {
  1328.  
  1329.             if (!(fproc = (*teData)->fastKeys)) {
  1330.                 if (refig) {
  1331.                     CTEAdjustTEBottom(te);
  1332.                     CTEAdjustScrollValues(te);
  1333.                 }
  1334.                 return(retval);
  1335.             }                        /* No fast keys looping proc defined, so leave. */
  1336.  
  1337.             if ((gSystemVersion >= 0x0700) && (HMGetBalloons())) {
  1338.                 if (refig) {
  1339.                     CTEAdjustTEBottom(te);
  1340.                     CTEAdjustScrollValues(te);
  1341.                 }
  1342.                 return(retval);
  1343.             }                        /* Don't call OSEventAvail if balloons are active, since
  1344.                                     ** the help manager may move a balloon when it is called.
  1345.                                     ** If we moved balloons now, that might be bad, since it
  1346.                                     ** is likely that BeginContent was called prior to getting
  1347.                                     ** here.  BeginContent calls BeginUpdate, which munges the
  1348.                                     ** visRgn.  If balloons were managed, then visRgns would get
  1349.                                     ** recalculated, and this would mess up our munged balloon. */
  1350.  
  1351.             event = &lclEvent;
  1352.             if (!OSEventAvail((mDownMask | keyDownMask | autoKeyMask), event)) {
  1353.                 if (refig) {
  1354.                     CTEAdjustTEBottom(te);
  1355.                     CTEAdjustScrollValues(te);
  1356.                 }
  1357.                 return(retval);
  1358.             }
  1359.  
  1360.             if (kproc) {
  1361.                 handled = 0;
  1362.                 if ((*kproc)(te, event, &handled)) {
  1363.                     if (refig) {
  1364.                         CTEAdjustTEBottom(te);
  1365.                         CTEAdjustScrollValues(te);
  1366.                     }
  1367.                     return(retval);
  1368.                 }
  1369.             }
  1370.  
  1371.             if (!(*fproc)(te, event)) {
  1372.                 if (refig) {
  1373.                     CTEAdjustTEBottom(te);
  1374.                     CTEAdjustScrollValues(te);
  1375.                 }
  1376.                 return(retval);
  1377.             }
  1378.  
  1379.             GetOSEvent((mDownMask | keyDownMask | autoKeyMask), event);
  1380.         }
  1381.  
  1382.         maxTextLen = (*teData)->maxTextLen;
  1383.         key        = event->message & charCodeMask;
  1384.         selStart   = (*te)->selStart;
  1385.         selEnd     = (*te)->selEnd;
  1386.         if (selStart > selEnd) {
  1387.             selStart = selEnd;
  1388.             selEnd = (*te)->selStart;
  1389.         }
  1390.         textSelected = (selStart != selEnd);
  1391.         arrowKey     = ((key >= chLeft) && (key <= chDown));
  1392.  
  1393.         if (
  1394.             (textSelected) ||                /* If selection range to be replaced or */
  1395.             (arrowKey) ||                    /* key is an arrow or                    */
  1396.             (key == 8) ||                    /* key is a delete or                   */
  1397.             ((*te)->teLength < maxTextLen)    /* we have space for the key...         */
  1398.         ) {
  1399.             tsmHandled = false;
  1400.             if (gUseTSMTE) {
  1401.                 tsmHandled = TSMEvent(event);
  1402.                 if (tsmHandled)
  1403.                     if (!arrowKey)
  1404.                         retval = 2;
  1405.             }
  1406.             if (!tsmHandled) {
  1407.                 if (arrowKey) {
  1408.                     (*teData)->newUndo = true;
  1409.                     TEKey(key, te);
  1410.                 }
  1411.                 else {
  1412.                     CTENewUndo(viewCtl, false);        /* Process the character... */
  1413.                     TEKey(key, te);
  1414.                     retval = 2;
  1415.                 }
  1416.             }
  1417.             refig = true;
  1418.         }
  1419.     }
  1420. }
  1421.  
  1422.  
  1423.  
  1424. static short    dummyCTEKey(WindowPtr window, EventRecord *event)
  1425. {
  1426. #ifndef __MWERKS__
  1427. #pragma unused (window, event)
  1428. #endif
  1429.     return(0);
  1430. }
  1431.  
  1432.  
  1433.  
  1434. /*****************************************************************************/
  1435.  
  1436.  
  1437.  
  1438. /* This function is used to move a TextEdit control.  Pass it the TextEdit
  1439. ** record to move, plus the new position.  It will move the TextEdit control,
  1440. ** along with any scrollbars the control may have.  All areas that need
  1441. ** updating are cleared and invalidated. */
  1442.  
  1443. #pragma segment TextEditControl
  1444. void    CTEMove(TEHandle teHndl, short newH, short newV)
  1445. {
  1446.     WindowPtr        oldPort;
  1447.     Rect            viewRct, brdrRct, rct;
  1448.     short            i, dx, dy, mode;
  1449.     Boolean            hScroll, vScroll;
  1450.     ControlHandle    viewCtl, ctl;
  1451.     CTEDataHndl        teData;
  1452.     char            vis;
  1453.  
  1454.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  1455.  
  1456.     GetPort(&oldPort);
  1457.     SetPort((*teHndl)->inPort);
  1458.  
  1459.     viewRct = (*viewCtl)->contrlRect;
  1460.     vis     = (*viewCtl)->contrlVis;
  1461.     teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  1462.     brdrRct = (*teData)->brdrRect;
  1463.     mode    = (*teData)->mode;
  1464.  
  1465.     dx = newH - viewRct.left;
  1466.     dy = newV - viewRct.top;
  1467.     if ((!dx) && (!dy)) return;
  1468.  
  1469.     hScroll = (mode & cteHScroll) ? 1 : 0;
  1470.     vScroll = (mode & cteVScroll) ? 1 : 0;
  1471.         /* Get enough info to determine if we need to fix the scrollbar sizes. */
  1472.  
  1473.     rct = viewRct;                /* Erase all of the old list control and scrollbars. */
  1474.     if (!EmptyRect(&brdrRct))
  1475.         UnionRect(&rct, &brdrRct, &rct);
  1476.     if (vScroll)
  1477.         rct.right += 15;
  1478.     if (hScroll)
  1479.         rct.bottom += 15;
  1480.     if (mode & cteShowActive)
  1481.         InsetRect(&rct, -4, -4);
  1482.     if (vis) {
  1483.         EraseRect(&rct);
  1484.         InvalRect(&rct);
  1485.     }
  1486.  
  1487.     for (i = 0; i < 2; ++i) {
  1488.         ctl = CTEScrollFromView(viewCtl, i);
  1489.         if (ctl) {
  1490.             rct = (*ctl)->contrlRect;
  1491.             MoveControl(ctl, rct.left + dx, rct.top + dy);
  1492.         }
  1493.     }
  1494.  
  1495.     OffsetRect(&viewRct, dx, dy);
  1496.     if (vis) InvalRect(&viewRct);
  1497.     OffsetRect(&brdrRct, dx, dy);
  1498.     if (vis) InvalRect(&brdrRct);
  1499.  
  1500.     (*viewCtl)->contrlRect = viewRct;
  1501.     (*teData)->brdrRect    = brdrRct;
  1502.  
  1503.     OffsetRect(&(*teHndl)->destRect, dx, dy);
  1504.     OffsetRect(&(*teHndl)->viewRect, dx, dy);
  1505.  
  1506.     viewRct.top  = viewRct.bottom - 16;
  1507.     viewRct.left = viewRct.right  - 16;
  1508.  
  1509.     if (vis)
  1510.         if (mode & (cteVScrollLessGrow - cteVScroll + cteHScrollLessGrow - cteHScroll))
  1511.             EraseRect(&viewRct);
  1512.  
  1513.     if (mode & (cteVScrollLessGrow - cteVScroll))
  1514.         OffsetRect(&viewRct, 16, 0);
  1515.     if (mode & (cteHScrollLessGrow - cteHScroll))
  1516.         OffsetRect(&viewRct, 0, 16);
  1517.     if (vis) InvalRect(&viewRct);
  1518.  
  1519.     SetPort(oldPort);
  1520. }
  1521.  
  1522.  
  1523.  
  1524. /*****************************************************************************/
  1525.  
  1526.  
  1527.  
  1528. /* Create a new TextEdit control.  See the comments at the beginning of this
  1529. ** file for more information.  Note that this function doesn't get a dummy,
  1530. ** as you really mean to have this code if you call it.  It calls CTEInitialize(),
  1531. ** just to make sure that the proc pointers are set to point to the real function,
  1532. ** instead of the dummy functions.  By having CLTENew() call CTEInitialize(), the
  1533. ** application won't have to worry about calling CTEInitialize().  By the time that
  1534. ** the application is using a TextEdit control, the proc pointers will be initialized. */
  1535.  
  1536. #pragma segment TextEditControl
  1537. OSErr    CTENew(short viewID, Boolean vis, WindowPtr window, TEHandle *teHndl, Rect *cRect, Rect *dRect,
  1538.                Rect *vRect, Rect *bRect, short maxTextLen, short mode)
  1539. {
  1540.     Rect            ctlRct, destRct, viewRct, brdrRct, scrollRct;
  1541.     WindowPtr        oldPort;
  1542.     TEHandle        te;
  1543.     short            width, height, lh, a;
  1544.     ControlHandle    viewCtl, hScrollCtl, vScrollCtl;
  1545.     CTEDataHndl        teData;
  1546.     TextStyle        styl;
  1547.     OSErr            err;
  1548.     TSMDocumentID    docID;
  1549.     TSMTERecHandle    tsmRec;
  1550.     static OSType    supportedInterfaceTypes[] = {kTSMTEInterfaceType};
  1551.  
  1552.     CTEInitialize();
  1553.  
  1554.     if (teHndl)
  1555.         *teHndl = nil;            /* Assume that we will fail. */
  1556.  
  1557.     GetPort(&oldPort);
  1558.     SetPort(window);
  1559.  
  1560.     ctlRct  = *cRect;
  1561.     destRct = *dRect;
  1562.     viewRct = *vRect;
  1563.     brdrRct = *bRect;
  1564.         /* Make sure that the rects are not in memory that may move. */
  1565.  
  1566.     te = TEStyleNew(&destRct, &viewRct);            /* Do the main thing. */
  1567.  
  1568.     err = noErr;
  1569.     viewCtl = hScrollCtl = vScrollCtl = nil;
  1570.         /* Prepare for various failures. */
  1571.  
  1572.     docID = nil;
  1573.  
  1574.     if (te) {        /* If we were able to create the TextEdit record... */
  1575.  
  1576.         if(gUseTSMTE) {
  1577.             if (!(err = NewTSMDocument(1, supportedInterfaceTypes, &docID, (long)&tsmRec))) {
  1578.                 (*tsmRec)->textH           = te;
  1579.                 (*tsmRec)->preUpdateProc  = nil;
  1580.                 (*tsmRec)->postUpdateProc = (TSMPostUpdateProcPtr)&TSMTEUpdateProc;
  1581.                 (*tsmRec)->updateFlag     = 0;
  1582.                 (*tsmRec)->refCon         = 0;
  1583.             }
  1584.         }
  1585.  
  1586.         if (mode & cteCenterJustify)
  1587.             TESetAlignment(1, te);
  1588.  
  1589.         if (mode & cteRightJustify)
  1590.             TESetAlignment(-1, te);
  1591.  
  1592.         TEGetStyle(0, &styl, &lh, &a, te);
  1593.         if (styl.tsFont == 1) {
  1594.             styl.tsFont = GetAppFont();
  1595.             styl.tsSize = GetDefFontSize();
  1596.             TESetStyle((doFont | doSize), &styl, false, te);
  1597.         }
  1598.  
  1599.         TEAutoView(true, te);
  1600.             /* Let TextEdit 3.0 do most of the scrolling work. */
  1601.  
  1602.         gDefaultClikLoopUPP = (*te)->clickLoop;
  1603. #if USES68KINLINES
  1604.         (*te)->clickLoop = (ProcPtr)ASMTECLIKLOOP;
  1605. #else
  1606.         if (!gClikLoopUPP) {
  1607.             gClikLoopUPP = NewTEClickLoopProc(PPCClikLoop);
  1608.             TESetClickLoop(gClikLoopUPP, te);
  1609.         }
  1610. #endif
  1611.         
  1612.  
  1613.         if (!gCDEF) {
  1614.             gCDEF = (cdefRsrcJMPHndl)GetResource('CDEF', (viewID / 16));
  1615.             if (!gCDEF) return(resNotFound);
  1616.  
  1617.             if (!gCTECtlUPP) {
  1618.                 gCTECtlUPP = NewControlDefProc(CTECtl);
  1619.             }
  1620.             (*gCDEF)->jmpAddress = (long)gCTECtlUPP;
  1621.             FlushInstructionCache();    /* Make sure that instruction caches don't kill us. */
  1622.         }
  1623.  
  1624.         if (mode & cteHScroll) {        /* Caller wants a horizontal scrollbar... */
  1625.             SetRect(&scrollRct, 0, 0, 100, 16);
  1626.             hScrollCtl = NewControl(window, &scrollRct, "\p", vis, 0, 0, 0, scrollBarProc, 0);
  1627.             if (hScrollCtl) {
  1628.                 MoveControl(hScrollCtl, brdrRct.left, brdrRct.bottom - 1);
  1629.                 width = brdrRct.right - brdrRct.left;
  1630.                 if (mode & (cteHScrollLessGrow - cteHScroll))
  1631.                     if (!(mode & cteVScroll))
  1632.                         width -= 15;
  1633.                 SizeControl(hScrollCtl, width, 16);
  1634.                     /* Line the scrollbar up with the borderRct. */
  1635.             }
  1636.             else err = resNotFound;
  1637.         }
  1638.  
  1639.         if (mode & cteVScroll) {        /* Caller wants a vertical scrollbar... */
  1640.             SetRect(&scrollRct, 0, 0, 16, 100);
  1641.             vScrollCtl = NewControl(window, &scrollRct, "\p", vis, 0, 0, 0, scrollBarProc, 0);
  1642.             if (vScrollCtl) {
  1643.                 MoveControl(vScrollCtl, brdrRct.right - 1, brdrRct.top);
  1644.                 height = brdrRct.bottom - brdrRct.top;
  1645.                 if (mode & (cteVScrollLessGrow - cteVScroll))
  1646.                     if (!(mode & cteHScroll))
  1647.                         height -= 15;
  1648.                 SizeControl(vScrollCtl, 16, height);
  1649.                     /* Line the scrollbar up with the borderRct. */
  1650.             }
  1651.             else err = resNotFound;
  1652.         }
  1653.  
  1654.         viewCtl = NewControl(window, &ctlRct, "\p", false, 0, 0, 0, viewID, (long)te);
  1655.             /* Use our custom view cdef.  It's wierd, but it's small. */
  1656.  
  1657.         if (!viewCtl)
  1658.             err = resNotFound;
  1659.         else {
  1660.             if (hScrollCtl)
  1661.                 SetControlReference(hScrollCtl, (long)viewCtl);
  1662.             if (vScrollCtl)
  1663.                 SetControlReference(vScrollCtl, (long)viewCtl);
  1664.             (*viewCtl)->contrlData = nil;
  1665.             teData = (CTEDataHndl)NewHandleClear(sizeof(CTEDataRec));
  1666.             if (teData) {
  1667.                 (*teData)->maxTextLen   = maxTextLen;
  1668.                 (*teData)->newUndo      = true;
  1669.                 (*teData)->mode         = mode;
  1670.                 (*teData)->brdrRect     = brdrRct;
  1671.                 (*teData)->brdrRect     = brdrRct;
  1672.                 if (!(mode & cteNoFastKeys))
  1673.                     (*teData)->fastKeys = GoFast;
  1674.                 (*teData)->docID        = docID;
  1675.                 (*viewCtl)->contrlData  = (Handle)teData;
  1676.             }
  1677.             else {
  1678.                 err = memFullErr;
  1679.                 if (docID)
  1680.                     DeleteTSMDocument(docID);
  1681.             }
  1682.         }
  1683.     }
  1684.     else err = memFullErr;
  1685.  
  1686.     SetPort(oldPort);
  1687.  
  1688.     if (err) {        /* Oops.  Somebody wasn't happy. */
  1689.         if (viewCtl)
  1690.             DisposeControl(viewCtl);
  1691.                 /* This also disposes of TextEdit handle! */
  1692.         else
  1693.             if (te)
  1694.                 TEDispose(te);
  1695.                     /* We have to dispose of the TextEdit handle ourselves if
  1696.                     ** creating the view control failed. */
  1697.  
  1698.         te = nil;        /* Indicate that there is no TextEdit control. */
  1699.  
  1700.         if (hScrollCtl)
  1701.             DisposeControl(hScrollCtl);
  1702.                 /* More clean-up. */
  1703.  
  1704.         if (vScrollCtl)
  1705.             DisposeControl(vScrollCtl);
  1706.                 /* And still more clean-up. */
  1707.     }
  1708.     else {
  1709.         if (mode & cteActive)
  1710.             CTEActivate(true, te);
  1711.  
  1712.         if (vis) ShowStyledControl(viewCtl);        /* Since everything worked, show the control. */
  1713.  
  1714.         if (mode & cteReadOnly) {
  1715.             if (!gNoCaretHookUPP) {
  1716. #if USES68KINLINES
  1717.                 gNoCaretHookUPP = (ProcPtr)ASMNOCARET;
  1718. #else
  1719.                 gNoCaretHookUPP = NewCaretHookProc(PPCNoCaret);
  1720. #endif
  1721.             }
  1722.             (*te)->caretHook = gNoCaretHookUPP;
  1723.                 /* If read-only, then disable caret for this TextEdit control. */
  1724.         }
  1725.  
  1726.         if (teHndl)
  1727.             *teHndl = te;
  1728.         CTEAdjustScrollValues(te);
  1729.             /* Give the scrollbars an initial value.  This is because the
  1730.             ** TextEdit control could have been created with
  1731.             ** destRct.top < viewRct.top or destRct.left < viewRct.left.
  1732.             ** I don't know why anyone would want to, but it is legal.
  1733.             */
  1734.     }
  1735.  
  1736.     return(err);
  1737. }
  1738.  
  1739. static Boolean    GoFast(TEHandle teHndl, EventRecord *event)
  1740. {
  1741. #ifndef __MWERKS__
  1742. #pragma unused (teHndl)
  1743. #endif
  1744.  
  1745.     char    key;
  1746.  
  1747.     if (event->modifiers & cmdKey) return(false);
  1748.     key = event->message & charCodeMask;
  1749.     if (key == chTab) return(false);
  1750.  
  1751.     return(true);
  1752. }
  1753.  
  1754.  
  1755.  
  1756. /*****************************************************************************/
  1757.  
  1758.  
  1759.  
  1760. /* Save the data (if appropriate) so that user can undo. */
  1761.  
  1762. #pragma segment TextEditControl
  1763. void    CTENewUndo(ControlHandle viewCtl, Boolean alwaysNewUndo)
  1764. {
  1765.     TEHandle        teHndl;
  1766.     CTEDataHndl        teData;
  1767.     Handle            hText, uText;
  1768.     StScrpHandle    hStyl, uStyl;
  1769.  
  1770.     if (!viewCtl) return;
  1771.  
  1772.     teHndl = (TEHandle)GetControlReference(viewCtl);
  1773.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  1774.  
  1775.     if ((!alwaysNewUndo) && (!(*teData)->newUndo)) return;
  1776.         /* If there isn't a new undo to record, then just return. */
  1777.  
  1778.     hText = (*teHndl)->hText;
  1779.     hStyl = CTEGetFullStylScrap(teHndl);
  1780.     uText = (*teData)->undoText;
  1781.     uStyl = (*teData)->undoStyl;
  1782.         /* hText/hStyl is styled text in the TextEdit record that is being edited.  */
  1783.         /* uText/uStyl is the undo data (if any) prior to current edit task. */
  1784.  
  1785.     if (uText) {                /* Dump the old undo info, if any. */
  1786.         DisposeHandle(uText);
  1787.         (*teData)->undoText = nil;
  1788.     }
  1789.     if (uStyl) {
  1790.         DisposeHandle((Handle)uStyl);
  1791.         (*teData)->undoStyl = nil;
  1792.     }
  1793.  
  1794.     if (!hStyl) return;
  1795.         /* Not enough ram to record undo, so leave. */
  1796.  
  1797.     uText = hText;
  1798.     if (HandToHand(&uText)) {            /* Copy the text (if ram available). */
  1799.         DisposeHandle((Handle)hStyl);
  1800.         return;                            /* Not enough ram to record undo. */
  1801.     }
  1802.  
  1803.     (*teData)->undoText     = uText;
  1804.     (*teData)->undoStyl     = hStyl;
  1805.     (*teData)->newUndo      = false;
  1806.     (*teData)->undoSelStart = (*teHndl)->selStart;
  1807.     (*teData)->undoSelEnd   = (*teHndl)->selEnd;
  1808. }
  1809.  
  1810.  
  1811.  
  1812. /*****************************************************************************/
  1813.  
  1814.  
  1815.  
  1816. /* Get the next TextEdit control in the window.  You pass it a control handle
  1817. ** for the view control, or nil to start at the beginning of the window.
  1818. ** It returns both a TextEdit handle and the view control handle for that
  1819. ** TextEdit record.  If none is found, nil is returned.  This allows you to
  1820. ** repeatedly call this function and walk through all the TextEdit controls
  1821. ** in a window. */
  1822.  
  1823. #pragma segment TextEditControl
  1824. ControlHandle    CTENext(WindowPtr window, TEHandle *teHndl, ControlHandle ctl, short dir, Boolean justActive)
  1825. {
  1826.     short            i;
  1827.     ControlHandle    nextCtl, priorCtl;
  1828.  
  1829.     if (teHndl)
  1830.         *teHndl = nil;
  1831.  
  1832.     if (!window) return(nil);
  1833.     if (!gCDEF)  return(nil);
  1834.  
  1835.     if (dir > 0) {
  1836.         if (!ctl)
  1837.             ctl = ((WindowPeek)window)->controlList;
  1838.         else
  1839.             ctl = (*ctl)->nextControl;
  1840.         while (ctl) {
  1841.             if ((!justActive) || ((*ctl)->contrlVis)) {
  1842.                 if ((!justActive) || ((*ctl)->contrlHilite != 255)) {
  1843.                     if (*(*ctl)->contrlDefProc == *(Handle)gCDEF) {
  1844.                             /* The handle may be locked, which means that the hi-bit
  1845.                             ** may be on, thus invalidating the compare.  Dereference the
  1846.                             ** handles to get rid of this possibility. */
  1847.                         if (teHndl)
  1848.                             *teHndl = (TEHandle)GetControlReference(ctl);
  1849.                         return(ctl);
  1850.                     }
  1851.                 }
  1852.             }
  1853.             ctl = (*ctl)->nextControl;
  1854.         }
  1855.         return(ctl);
  1856.     }
  1857.  
  1858.     nextCtl = ((WindowPeek)window)->controlList;
  1859.     for (i = 1, priorCtl = nil; ;nextCtl = (*nextCtl)->nextControl, ++i) {
  1860.         if ((!nextCtl) || (nextCtl == ctl)) {
  1861.             if (priorCtl)
  1862.                 if (teHndl)
  1863.                     *teHndl = (TEHandle)GetControlReference(priorCtl);
  1864.             return(priorCtl);
  1865.         }
  1866.         if ((!justActive) || ((*nextCtl)->contrlVis)) {
  1867.             if ((!justActive) || ((*nextCtl)->contrlHilite != 255)) {
  1868.                 if (*(*nextCtl)->contrlDefProc == *(Handle)gCDEF)
  1869.                     priorCtl = nextCtl;
  1870.             }
  1871.         }
  1872.     }
  1873. }
  1874.  
  1875.  
  1876.  
  1877. static ControlHandle    dummyCTENext(WindowPtr window, TEHandle *teHndl, ControlHandle ctl, short dir, Boolean justActive)
  1878. {
  1879. #ifndef __MWERKS__
  1880. #pragma unused (window, ctl, dir, justActive)
  1881. #endif
  1882.     *teHndl = nil;
  1883.     return(nil);
  1884. }
  1885.  
  1886.  
  1887.  
  1888. /*****************************************************************************/
  1889.  
  1890.  
  1891.  
  1892. /* Return the number of lines of text.  This is because there is a bug in
  1893. ** TextEdit where the number of lines returned is incorrect if the text
  1894. ** ends with a c/r.  This function adjusts for this bug. */
  1895.  
  1896. #pragma segment TextEditControl
  1897. short    CTENumTextLines(TEHandle teHndl)
  1898. {
  1899.     short    lines;
  1900.     char    *cptr;
  1901.  
  1902.     if (!teHndl) return(0);
  1903.  
  1904.     lines = (*teHndl)->nLines;
  1905.  
  1906.     cptr = *((*teHndl)->hText);        /* Pointer to first TextEdit character. */
  1907.     if (cptr[(*teHndl)->teLength - 1] == kCrChar)
  1908.         ++lines;
  1909.             /* Since nLines isn’t right if the last character is a return,
  1910.             ** check for that case and fix it. */
  1911.  
  1912.     return(lines);
  1913. }
  1914.  
  1915.  
  1916.  
  1917. /*****************************************************************************/
  1918.  
  1919.  
  1920.  
  1921. /* Use this function to print the contents of a TextEdit record.  Pass it a
  1922. ** TextEdit handle, a pointer to a text offset, and a pointer to a rect to
  1923. ** print the text in.  The offset should be initialized to what character
  1924. ** in the TextEdit record you wish to start printing at (most likely 0).
  1925. ** The print function prints as much text as will fit in the rect, and
  1926. ** then updates the offset to tell you what is the first character that didn't
  1927. ** print.  You can then call the print function again with another rect with
  1928. ** this new offset, and it will print the text starting at the new offset.
  1929. ** This method is very useful when a single TextEdit record is longer than a
  1930. ** single page, and you wish the text to break at the end of the page.
  1931. ** The bottom of rect is also updated, along with the offset.  The bottom edge
  1932. ** of the rect is changed to reflect the actual bottom of the text printed.
  1933. ** This is useful because the rect passed in didn't necessarily hold an
  1934. ** integer number of lines of text.  The bottom of the rect is adjusted so
  1935. ** it exactly holds complete lines of text.
  1936. ** It is also possible that the rect could hold substantially more lines of
  1937. ** text than there are remaining.  Again, in this situation, the bottom of
  1938. ** rect is adjusted so that the rect tightly bounds the text printed.
  1939. ** The remaining piece of information passed back is an indicator that the
  1940. ** text through the end of the TextEdit record was printed.  When the end
  1941. ** of the text is reached, the offset for the next text to be printed is
  1942. ** returned as -1.  This indicates that processing of the TextEdit record
  1943. ** is complete. */
  1944.  
  1945. #pragma segment TextEditControl
  1946. OSErr    CTEPrint(TEHandle teHndl, short *teOffset, Rect *teRct)
  1947. {
  1948.     short            len, offset, numLines, rctHeight, selStart, selEnd, lnum, y, lh;
  1949.     Handle            hText;
  1950.     Rect            keepDestRct, keepViewRct;
  1951.     WindowPtr        printPort;
  1952.     StScrpHandle    fullStyl, partStyl;
  1953.  
  1954.     if (!teHndl) return(noErr);
  1955.  
  1956.     len = (*teHndl)->teLength;
  1957.     if ((offset = *teOffset) >= len) {
  1958.         *teOffset = -1;                    /* We are offset further than we have text. */
  1959.         teRct->bottom = teRct->top;        /* Empty rect, since no text to draw.  */
  1960.         return(noErr);                    /* Just say that we have no more text. */
  1961.     }
  1962.  
  1963.     if (!(hText = NewHandle(len - offset))) return(memFullErr);
  1964.         /* Can't make part-text handle, so leave. */
  1965.  
  1966.     BlockMove((*(*teHndl)->hText) + offset, *hText, len - offset);
  1967.         /* hText now holds all characters after offset. */
  1968.  
  1969.     fullStyl = CTEGetFullStylScrap(teHndl);
  1970.     if (!fullStyl) {
  1971.         DisposeHandle(hText);        /* Couldn't get styles, so clean up and leave. */
  1972.         return(memFullErr);
  1973.     }
  1974.  
  1975.     partStyl = fullStyl;                    /* This assignment tests for styled TE, and if there */
  1976.     if (partStyl) {                            /* is none, then partStyl gets initialized to nil.   */
  1977.  
  1978.         selStart = (*teHndl)->selStart;        /* Get all styles after the offset. */
  1979.         selEnd   = (*teHndl)->selEnd;
  1980.         (*teHndl)->selStart = offset;
  1981.         (*teHndl)->selEnd   = (*teHndl)->teLength;
  1982.         partStyl = TEGetStyleScrapHandle(teHndl);
  1983.         (*teHndl)->selStart = selStart;
  1984.         (*teHndl)->selEnd   = selEnd;
  1985.         if (!partStyl) {
  1986.             DisposeHandle((Handle)fullStyl);
  1987.             DisposeHandle(hText);
  1988.             return(memFullErr);
  1989.         }
  1990.     }
  1991.  
  1992.     keepDestRct = (*teHndl)->destRect;
  1993.     keepViewRct = (*teHndl)->viewRect;
  1994.     gTEWindow   = (*teHndl)->inPort;
  1995.         /* Cache some information from the TextEdit record. */
  1996.  
  1997.     GetPort(&printPort);
  1998.     (*teHndl)->inPort = printPort;
  1999.     (*teHndl)->destRect = (*teHndl)->viewRect = *teRct;
  2000.         /* Install the print rect into the TextEdit record so CTESwapText
  2001.         ** recalcs against the print text. */
  2002.  
  2003.     hText = CTESwapText(teHndl, hText, partStyl, false);
  2004.     DisposeHandle((Handle)partStyl);
  2005.         /* We now have all of the text starting at offset formatted correctly in the print rect. */
  2006.  
  2007.     rctHeight = teRct->bottom - teRct->top;
  2008.     numLines  = CTENumTextLines(teHndl);
  2009.     for (y = 0, lnum = 1; lnum <= numLines; ++lnum) {
  2010.         lh = CTEGetLineHeight(teHndl, lnum, nil);
  2011.         if (y + lh > rctHeight) break;
  2012.         y += lh;
  2013.     }
  2014.     teRct->bottom = teRct->top + y;
  2015.     
  2016.     (*teHndl)->destRect = (*teHndl)->viewRect = *teRct;
  2017.         /* We now have the minimum rectangle to hold as much of the text
  2018.         ** as would fit into the rectangle passed in.  The final calc on
  2019.         ** the rect prevents partial lines from being drawn. */
  2020.  
  2021.     TEUpdate(teRct, teHndl);        /* Draw this portion of the text. */
  2022.  
  2023.     if (--lnum >= numLines)
  2024.         *teOffset = -1;
  2025.             /* Printed the last of the text for this record. */
  2026.     else
  2027.         *teOffset = (*teHndl)->lineStarts[lnum] + offset;
  2028.             /* Offset to the first character not printed. */
  2029.  
  2030.     (*teHndl)->inPort   = gTEWindow;
  2031.     gTEWindow           = nil;
  2032.     (*teHndl)->destRect = keepDestRct;
  2033.     (*teHndl)->viewRect = keepViewRct;
  2034.  
  2035.     DisposeHandle(CTESwapText(teHndl, hText, fullStyl, false));
  2036.     DisposeHandle((Handle)fullStyl);
  2037.  
  2038.     return(noErr);            /* Everything worked. */
  2039. }
  2040.  
  2041.  
  2042.  
  2043. /*****************************************************************************/
  2044.  
  2045.  
  2046.  
  2047. /* Return if the TextEdit control is read/write (true) or read-only (false). */
  2048.  
  2049. #pragma segment TextEditControl
  2050. Boolean    CTEReadOnly(TEHandle teHndl)
  2051. {
  2052.     if (teHndl)
  2053.         if (gNoCaretHookUPP)
  2054.             if ((*teHndl)->caretHook == gNoCaretHookUPP)
  2055.                 return(true);
  2056.  
  2057.     return(false);
  2058. }
  2059.  
  2060.  
  2061.  
  2062. /*****************************************************************************/
  2063.  
  2064.  
  2065.  
  2066. /* Return the control handle for the TextEdit control's scrollbar, either
  2067. ** vertical or horizontal.  If the scrollbar doesn't, nil is returned. */
  2068.  
  2069. #pragma segment TextEditControl
  2070. ControlHandle    CTEScrollFromTE(TEHandle teHndl, Boolean vertScroll)
  2071. {
  2072.     ControlHandle    viewCtl;
  2073.  
  2074.     if (!(viewCtl = CTEViewFromTE(teHndl))) return(nil);
  2075.  
  2076.     return(CTEScrollFromView(viewCtl, vertScroll));
  2077. }
  2078.  
  2079.  
  2080.  
  2081. /*****************************************************************************/
  2082.  
  2083.  
  2084.  
  2085. /* Return the control handle for the scrollbar related to the view control,
  2086. ** either horizontal or vertical.  If the scrollbar doesn't exist, return nil. */
  2087.  
  2088. #pragma segment TextEditControl
  2089. ControlHandle    CTEScrollFromView(ControlHandle viewCtl, Boolean vertScroll)
  2090. {
  2091.     ControlHandle    ctl;
  2092.     WindowPtr        window;
  2093.     Boolean            vert;
  2094.  
  2095.     if (!viewCtl) return(nil);
  2096.  
  2097.     window = (*viewCtl)->contrlOwner;
  2098.     ctl    = ((WindowPeek)window)->controlList;
  2099.  
  2100.     for (; ctl;) {
  2101.         if ((ControlHandle)GetControlReference(ctl) == viewCtl) {
  2102.             vert = false;
  2103.             if ((*ctl)->contrlRect.right == (*ctl)->contrlRect.left + 16)
  2104.                 vert = true;
  2105.             if (vert == vertScroll) return(ctl);
  2106.         }
  2107.         ctl = (*ctl)->nextControl;
  2108.     }
  2109.     return(nil);
  2110. }
  2111.  
  2112.  
  2113.  
  2114. /*****************************************************************************/
  2115.  
  2116.  
  2117.  
  2118. /* A TextEdit control can have an optional key filter, which is called whenever
  2119. ** CTEKey() is called.  If you pass in nil, then the filtering is turned off.
  2120. ** This allows individual TextEdit controls to handle their own filtering.
  2121. ** The filter procedure is of the form:
  2122. **     Boolean (*CTEKeyFilterProcPtr)(TEHandle teHndl, EventRecord *event, short *handled);
  2123. ** If true is returned, then CTEKey() is aborted, and the value in "handled" is
  2124. ** returned.  By having a separate abort value and return value, you can determine
  2125. ** if processing of the event should be continued or not, independent of whether
  2126. ** or not you aborted CTEKey(). */
  2127.  
  2128. #pragma segment TextEditControl
  2129. void    CTESetKeyFilter(TEHandle teHndl, CTEKeyFilterProcPtr proc)
  2130. {
  2131.     ControlHandle    viewCtl;
  2132.     CTEDataHndl        teData;
  2133.  
  2134.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  2135.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2136.     (*teData)->keyFilter = proc;
  2137. }
  2138.  
  2139.  
  2140.  
  2141. /*****************************************************************************/
  2142.  
  2143.  
  2144.  
  2145. #pragma segment TextEditControl
  2146. void    CTESetFastKeys(TEHandle teHndl, CTEFastKeysProcPtr proc)
  2147. {
  2148.     ControlHandle    viewCtl;
  2149.     CTEDataHndl        teData;
  2150.  
  2151.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  2152.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2153.     (*teData)->fastKeys = proc;
  2154. }
  2155.  
  2156.  
  2157.  
  2158. /*****************************************************************************/
  2159.  
  2160.  
  2161.  
  2162. /* Select a range of text.  TESetSelect can't be used alone because it doesn't
  2163. ** update the scrollbars.  This function calls TESetSelect, and then fixes up
  2164. ** the scrollbars. */
  2165.  
  2166. #pragma segment TextEditControl
  2167. void    CTESetSelect(short start, short end, TEHandle teHndl)
  2168. {
  2169.     WindowPtr        oldPort;
  2170.     ControlHandle    viewCtl;
  2171.     CTEDataHndl        teData;
  2172.  
  2173.     if (teHndl) {
  2174.         GetPort(&oldPort);
  2175.         SetPort((*teHndl)->inPort);
  2176.         TESetSelect(start, end, teHndl);
  2177.         CTEAdjustScrollValues(teHndl);
  2178.         viewCtl = CTEViewFromTE(teHndl);
  2179.         if (viewCtl) {
  2180.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2181.             (*teData)->newUndo = true;
  2182.         }
  2183.         SetPort(oldPort);
  2184.     }
  2185. }
  2186.  
  2187.  
  2188.  
  2189. static void    dummyCTESetSelect(short start, short end, TEHandle teHndl)
  2190. {
  2191. #ifndef __MWERKS__
  2192. #pragma unused (start, end, teHndl)
  2193. #endif
  2194. }
  2195.  
  2196.  
  2197.  
  2198. /*****************************************************************************/
  2199.  
  2200.  
  2201.  
  2202. /* Show the designated TextEdit control and related scrollbars. */
  2203.  
  2204. #pragma segment TextEditControl
  2205. void    CTEShow(TEHandle teHndl)
  2206. {
  2207.     ControlHandle    viewCtl, scrollCtl;
  2208.     short            i;
  2209.  
  2210.     viewCtl = CTEViewFromTE(teHndl);
  2211.     if (viewCtl) {
  2212.         ShowStyledControl(viewCtl);
  2213.         for (i = 0; i < 2; i++) {
  2214.             scrollCtl = CTEScrollFromView(viewCtl, i);
  2215.             if (scrollCtl)
  2216.                 ShowStyledControl(scrollCtl);
  2217.         }
  2218.     }
  2219. }
  2220.  
  2221.  
  2222.  
  2223. /*****************************************************************************/
  2224.  
  2225.  
  2226.  
  2227. /* This function is used to resize a TextEdit control.  Pass it the TextEdit
  2228. ** record to resize, plus the new horizontal and vertical size.  It will
  2229. ** resize the TextEdit control, realign the text, if necessary, plus it will
  2230. ** resize and adjust any scrollbars the TextEdit control may have.  All areas
  2231. ** that need updating are cleared and invalidated. */
  2232.  
  2233. #pragma segment TextEditControl
  2234. void    CTESize(TEHandle teHndl, short newH, short newV, Boolean newDest)
  2235. {
  2236.     WindowPtr        oldPort;
  2237.     Rect            viewRct, brdrRct, teViewRct, oldTeViewRct, rct;
  2238.     short            i, dx, dy, mode, hScroll, vScroll;
  2239.     ControlHandle    viewCtl, ctl[2];
  2240.     CTEDataHndl        teData;
  2241.     RgnHandle        rgn1, rgn2;
  2242.     char            vis;
  2243.  
  2244.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  2245.  
  2246.     GetPort(&oldPort);
  2247.     SetPort((*teHndl)->inPort);
  2248.  
  2249.     viewRct = (*viewCtl)->contrlRect;
  2250.     vis     = (*viewCtl)->contrlVis;
  2251.     teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  2252.     brdrRct = (*teData)->brdrRect;
  2253.     mode    = (*teData)->mode;
  2254.  
  2255.     dx = newH - (viewRct.right  - viewRct.left);
  2256.     dy = newV - (viewRct.bottom - viewRct.top);
  2257.     if ((!dx) && (!dy)) return;
  2258.  
  2259.     hScroll = (mode & cteHScroll) ? 1 : 0;
  2260.     vScroll = (mode & cteVScroll) ? 1 : 0;
  2261.         /* Get enough info to determine if we need to fix the scrollbar sizes. */
  2262.  
  2263.     rct = viewRct;                /* Erase all of the old list control and scrollbars. */
  2264.     if (!EmptyRect(&brdrRct))
  2265.         UnionRect(&rct, &brdrRct, &rct);
  2266.     if (vScroll)
  2267.         rct.right += 15;
  2268.     if (hScroll)
  2269.         rct.bottom += 15;
  2270.     if (mode & cteShowActive)
  2271.         InsetRect(&rct, -4, -4);
  2272.     if (vis) {
  2273.         EraseRect(&rct);
  2274.         InvalRect(&rct);
  2275.     }
  2276.  
  2277.     for (i = 0; i < 2; ++i) {
  2278.         ctl[i] = CTEScrollFromView(viewCtl, i);
  2279.         if (ctl[i]) {
  2280.             rct = (*ctl[i])->contrlRect;
  2281.             if (i) {
  2282.                 HideControl(ctl[i]);
  2283.                 SizeControl(ctl[i], rct.right - rct.left, rct.bottom - rct.top + dy);
  2284.                 MoveControl(ctl[i], rct.left + dx, rct.top);
  2285.             }
  2286.             else {
  2287.                 HideControl(ctl[i]);
  2288.                 SizeControl(ctl[i], rct.right - rct.left + dx, rct.bottom - rct.top);
  2289.                 MoveControl(ctl[i], rct.left, rct.top + dy);
  2290.             }
  2291.         }
  2292.     }        /* Reposition the scrollbars, if we have any. */
  2293.  
  2294.     if (vis) InvalRect(&viewRct);        /* Resize our view control. */
  2295.     viewRct.right  += dx;
  2296.     viewRct.bottom += dy;
  2297.     (*viewCtl)->contrlRect = viewRct;
  2298.     if (vis) InvalRect(&viewRct);
  2299.  
  2300.     if (vis) InvalRect(&brdrRct);        /* Resize our border rect. */
  2301.     brdrRct.right  += dx;
  2302.     brdrRct.bottom += dy;
  2303.     (*teData)->brdrRect = brdrRct;
  2304.     if (vis) InvalRect(&brdrRct);
  2305.  
  2306.     teViewRct = oldTeViewRct = (*teHndl)->viewRect;        /* Resize TextEdit viewRect. */
  2307.     teViewRct.right  += dx;
  2308.     teViewRct.bottom += dy;
  2309.     (*teHndl)->viewRect = teViewRct;
  2310.  
  2311.     if (newDest) {        /* Resize TextEdit destRect, if so indicated. */
  2312.         (*teHndl)->destRect.right  += dx;
  2313.         (*teHndl)->destRect.bottom += dy;
  2314.         TECalText(teHndl);
  2315.         if (vis) {
  2316.             EraseRect(&oldTeViewRct);        /* Redraw the whole thing if destRect changes. */
  2317.             InvalRect(&oldTeViewRct);
  2318.         }
  2319.     }
  2320.  
  2321.     if (vis) {
  2322.         rgn1 = NewRgn();
  2323.         rgn2 = NewRgn();
  2324.         RectRgn(rgn1, &oldTeViewRct);        /* Clear old areas if we are shrinking. */
  2325.         RectRgn(rgn2, &teViewRct);
  2326.         DiffRgn(rgn1, rgn2, rgn2);
  2327.         EraseRgn(rgn2);
  2328.         InvalRgn(rgn2);
  2329.         RectRgn(rgn2, &teViewRct);            /* Update new areas if we are growing. */
  2330.         DiffRgn(rgn2, rgn1, rgn2);
  2331.         InvalRgn(rgn2);
  2332.         DisposeRgn(rgn1);
  2333.         DisposeRgn(rgn2);
  2334.     }
  2335.  
  2336.     if (vis)
  2337.         for (i = 0; i < 2; ++i)
  2338.             if (ctl[i])
  2339.                 ShowStyledControl(ctl[i]);
  2340.                     /* Show the controls in their new position. */
  2341.  
  2342.     if (mode & (cteVScrollLessGrow - cteVScroll + cteHScrollLessGrow - cteHScroll)) {
  2343.         rct = viewRct;
  2344.         rct.top  = rct.bottom - 16;
  2345.         rct.left = rct.right - 16;
  2346.         if (mode & (cteVScrollLessGrow - cteVScroll))
  2347.             OffsetRect(&rct, 16, 0);
  2348.         if (mode & (cteHScrollLessGrow - cteHScroll))
  2349.             OffsetRect(&rct, 0, 16);
  2350.         if (vis) {
  2351.             EraseRect(&rct);
  2352.             InvalRect(&rct);
  2353.         }
  2354.     }
  2355.  
  2356.     CTEAdjustTEBottom(teHndl);
  2357.     CTEAdjustScrollValues(teHndl);
  2358.  
  2359.     SetPort(oldPort);
  2360. }
  2361.  
  2362.  
  2363.  
  2364. /*****************************************************************************/
  2365.  
  2366.  
  2367.  
  2368. /* Swap the TextEdit text handle with the text handle passed in. */
  2369.  
  2370. #pragma segment TextEditControl
  2371. Handle    CTESwapText(TEHandle teHndl, Handle newText, StScrpHandle styl, Boolean update)
  2372. {
  2373.     WindowPtr        oldPort;
  2374.     Handle            oldText;
  2375.     Rect            destRct, viewRct;
  2376.     TextStyle        srun;
  2377.     ScrpSTElement    s;
  2378.     ControlHandle    viewCtl;
  2379.     CTEDataHndl        teData;
  2380.     RgnHandle        oldClip, newClip;
  2381.  
  2382.     if (!teHndl) return(nil);
  2383.  
  2384.     GetPort(&oldPort);
  2385.     SetPort((*teHndl)->inPort);
  2386.  
  2387.     oldText = (*teHndl)->hText;
  2388.     HandToHand(&oldText);
  2389.  
  2390.     HLock(newText);
  2391.     TESetText(*newText, 0, teHndl);                            /* Make there be only 1 style run. */
  2392.     TESetText(*newText, GetHandleSize(newText), teHndl);    /* Put the correct text in the record. */
  2393.     DisposeHandle(newText);
  2394.  
  2395.     viewCtl = CTEViewFromTE(teHndl);
  2396.     teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  2397.     if (!((*teData)->mode & cteRightJustify)) {
  2398.         if (!(*viewCtl)->contrlVis) {
  2399.             GetClip(oldClip = NewRgn());
  2400.             SetClip(newClip = NewRgn());
  2401.         }
  2402.         TESetSelect(0, 0, teHndl);
  2403.         if (!(*viewCtl)->contrlVis) {
  2404.             SetClip(oldClip);
  2405.             DisposeRgn(oldClip);
  2406.             DisposeRgn(newClip);
  2407.         }
  2408.     }
  2409.  
  2410.     if (styl) {
  2411.         CTESetStylScrap(0, (*teHndl)->teLength, styl, teHndl);        /* Apply style to all text. */
  2412.         if ((*teHndl)->selStart)                                    /* Apply style to caret loc. */
  2413.             s = (*styl)->scrpStyleTab[0];
  2414.         else
  2415.             s = (*styl)->scrpStyleTab[(*styl)->scrpNStyles - 1];
  2416.         srun.tsFont  = s.scrpFont;
  2417.         srun.tsFace  = s.scrpFace;
  2418.         srun.tsSize  = s.scrpSize;
  2419.         srun.tsColor = s.scrpColor;
  2420.         TESetStyle(doAll, &srun, false, teHndl);
  2421.     }
  2422.  
  2423.     GetClip(oldClip = NewRgn());        /* Force the nullStyle to become active. */
  2424.     SetClip(newClip = NewRgn());        /* This also resizes the caret to reflect nullStyle size. */
  2425.     TEKey(' ', teHndl);
  2426.     TEKey(8, teHndl);
  2427.     SetClip(oldClip);
  2428.     DisposeRgn(oldClip);
  2429.     DisposeRgn(newClip);
  2430.  
  2431.     TECalText(teHndl);
  2432.  
  2433.     if (update) {
  2434.         destRct = (*teHndl)->destRect;
  2435.         viewRct = (*teHndl)->viewRect;
  2436.  
  2437.         OffsetRect(&destRct,
  2438.             viewRct.left - destRct.left,
  2439.             viewRct.top  - destRct.top);
  2440.  
  2441.         (*teHndl)->destRect = destRct;
  2442.         (*teHndl)->selStart = (*teHndl)->selEnd = 0;
  2443.  
  2444.         CTEUpdate(teHndl, CTEViewFromTE(teHndl), false);
  2445.     }
  2446.  
  2447.     CTEAdjustTEBottom(teHndl);        /* Fix these things up, whether showing or not. */
  2448.     CTEAdjustScrollValues(teHndl);
  2449.  
  2450.     SetPort(oldPort);
  2451.     return(oldText);
  2452. }
  2453.  
  2454.  
  2455.  
  2456. /*****************************************************************************/
  2457.  
  2458.  
  2459.  
  2460. /* Return information for the currently active TextEdit control.  The currently
  2461. ** active TextEdit control is stored in gActiveTEHndl, and can be accessed
  2462. ** directly.  If gActiveTEHndl is nil, then there is no currently active one.
  2463. ** The information that we return is the viewRect and window of the active
  2464. ** TextEdit control.  This is information that could be gotten directly, but
  2465. ** this call makes it a little more convenient. */
  2466.  
  2467. #pragma segment TextEditControl
  2468. WindowPtr    CTETargetInfo(TEHandle *teHndl, Rect *teView)
  2469. {
  2470.     if (teView)
  2471.         SetRect(teView, 0, 0, 0, 0);
  2472.  
  2473.     if (teHndl)
  2474.         *teHndl = gActiveTEHndl;
  2475.  
  2476.     if (!gActiveTEHndl) return(nil);
  2477.  
  2478.     if (teView)
  2479.         *teView = (*gActiveTEHndl)->viewRect;
  2480.  
  2481.     return((*gActiveTEHndl)->inPort);
  2482. }
  2483.  
  2484.  
  2485.  
  2486. /*****************************************************************************/
  2487.  
  2488.  
  2489.  
  2490. /* Perform an undo function for the TextEdit control. */
  2491.  
  2492. #pragma segment TextEditControl
  2493. ControlHandle    CTEUndo(void)
  2494. {
  2495.     TEHandle        teHndl;
  2496.     ControlHandle    viewCtl;
  2497.     CTEDataHndl        teData;
  2498.     Handle            hText, uText;
  2499.     StScrpHandle    hStyl, uStyl;
  2500.     short            oldStart, oldEnd;
  2501.  
  2502.     if (!(teHndl = gActiveTEHndl)) return(nil);
  2503.  
  2504.     viewCtl = CTEViewFromTE(teHndl);
  2505.     if (viewCtl) {
  2506.         oldStart = (*teHndl)->selStart;
  2507.         oldEnd   = (*teHndl)->selEnd;
  2508.  
  2509.         (*teHndl)->selStart = (*teHndl)->selEnd = 0;
  2510.  
  2511.         teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2512.         hText  = (*teHndl)->hText;
  2513.         uText  = (*teData)->undoText;
  2514.         if (!uText) return(nil);        /* There is no undo yet.  Getting called in this state is
  2515.                                         ** actually an error, but we check, just in case. */
  2516.  
  2517.         hStyl = CTEGetFullStylScrap(teHndl);
  2518.         uStyl = (*teData)->undoStyl;
  2519.  
  2520.         (*teData)->undoText = CTESwapText(teHndl, (*teData)->undoText, uStyl, false);
  2521.         DisposeHandle((Handle)uStyl);
  2522.         (*teData)->undoStyl = hStyl;
  2523.  
  2524.         CTEUpdate(teHndl, viewCtl, false);
  2525.         TESetSelect((*teData)->undoSelStart, (*teData)->undoSelEnd, teHndl);
  2526.         CTEAdjustTEBottom(teHndl);
  2527.         CTEAdjustScrollValues(teHndl);
  2528.  
  2529.         (*teData)->newUndo      = true;
  2530.         (*teData)->undoSelStart = oldStart;
  2531.         (*teData)->undoSelEnd   = oldEnd;
  2532.     }
  2533.  
  2534.     return(viewCtl);
  2535. }
  2536.  
  2537.  
  2538.  
  2539. /*****************************************************************************/
  2540.  
  2541.  
  2542.  
  2543. /* Draw the TextEdit control and frame. */
  2544.  
  2545. #pragma segment TextEditControl
  2546. void    CTEUpdate(TEHandle teHndl, ControlHandle ctl, Boolean justShowActive)
  2547. {
  2548.     WindowPtr    oldPort, tePort;
  2549.     Rect        viewRct, brdrRct;
  2550.     CTEDataHndl    teData;
  2551.     short        mode;
  2552.  
  2553.     if (teHndl) {
  2554.         if ((*ctl)->contrlVis) {
  2555.  
  2556.             GetPort(&oldPort);
  2557.             SetPort(tePort = (*teHndl)->inPort);
  2558.  
  2559.             teData  = (CTEDataHndl)(*ctl)->contrlData;
  2560.             mode    = (*teData)->mode;
  2561.             viewRct = (*teHndl)->viewRect;
  2562.             brdrRct = (*teData)->brdrRect;
  2563.  
  2564.             if (!justShowActive) {
  2565.                 if (!EmptyRect(&brdrRct)) {
  2566.                     if (!(mode & cteNoBorder)) {
  2567.                         FrameRect(&brdrRct);
  2568.                         InsetRect(&brdrRct, 1, 1);
  2569.                         EraseRect(&brdrRct);
  2570.                         InsetRect(&brdrRct, -1, -1);
  2571.                     }
  2572.                     else EraseRect(&brdrRct);
  2573.                 }
  2574.                 else EraseRect(&viewRct);
  2575.                 (*teHndl)->caretState &= 0xFF;
  2576.                 TEUpdate(&viewRct, teHndl);
  2577.             }
  2578.     
  2579.             if (mode & cteShowActive) {
  2580.                 if (!EmptyRect(&brdrRct)) {
  2581.                     InsetRect(&brdrRct, -3, -3);
  2582.                     if (mode & cteVScroll)
  2583.                         brdrRct.right  += 15;
  2584.                     if (mode & cteHScroll)
  2585.                         brdrRct.bottom += 15;
  2586.                     if ((!((WindowPeek)tePort)->hilited) || (teHndl != gActiveTEHndl))
  2587.                         PenPat((ConstPatternParam)&qd.white);
  2588.                     PenSize(2, 2);
  2589.                     FrameRect(&brdrRct);
  2590.                     InsetRect(&brdrRct, 2, 2);
  2591.                     PenSize(1, 1);
  2592.                     PenPat((ConstPatternParam)&qd.white);
  2593.                     FrameRect(&brdrRct);
  2594.                     PenNormal();
  2595.                 }
  2596.             }
  2597.  
  2598.             SetPort(oldPort);
  2599.         }
  2600.     }
  2601. }
  2602.  
  2603.  
  2604.  
  2605. /*****************************************************************************/
  2606.  
  2607.  
  2608.  
  2609. /* Return the control handle for the view control that owns the TextEdit
  2610. ** record.  Use this to find the view to do customizations such as changing
  2611. ** the update procedure for this TextEdit control. */
  2612.  
  2613. #pragma segment TextEditControl
  2614. ControlHandle    CTEViewFromTE(TEHandle teHndl)
  2615. {
  2616.     WindowPtr        window;
  2617.     ControlHandle    viewCtl;
  2618.     TEHandle        te;
  2619.  
  2620.     if (!teHndl) return(nil);
  2621.  
  2622.     if (!(window = gTEWindow))
  2623.         window = (WindowPtr)(*teHndl)->inPort;
  2624.  
  2625.     for (viewCtl = nil;;) {
  2626.  
  2627.         viewCtl = CTENext(window, &te, viewCtl, 1, false);
  2628.         if ((!viewCtl) || (te == teHndl)) return(viewCtl);
  2629.     }
  2630. }
  2631.  
  2632.  
  2633.  
  2634. static ControlHandle    dummyCTEViewFromTE(TEHandle teHndl)
  2635. {
  2636. #ifndef __MWERKS__
  2637. #pragma unused (teHndl)
  2638. #endif
  2639.     return(nil);
  2640. }
  2641.  
  2642.  
  2643.  
  2644. /*****************************************************************************/
  2645.  
  2646.  
  2647.  
  2648. /* Call this when a window with TextEdit controls is being activated.  This
  2649. ** will make the TextEdit control that was last active in this window the
  2650. ** active TextEdit control again. */
  2651.  
  2652. #pragma segment TextEditControl
  2653. TEHandle    CTEWindActivate(WindowPtr window, Boolean displayIt)
  2654. {
  2655.     short            hilite, scrollNum;
  2656.     ControlHandle    viewCtl, scrollCtl;
  2657.     TEHandle        te;
  2658.     CTEDataHndl        teData;
  2659.  
  2660.     if (!window) return(nil);
  2661.  
  2662.     hilite = 255;
  2663.     if (((WindowPeek)window)->hilited)
  2664.         hilite = 0;
  2665.  
  2666.     for (viewCtl = nil; (viewCtl = CTENext(window, &te, viewCtl, 1, true)) != nil;) {
  2667.  
  2668.         teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2669.         if (!((*teData)->mode & cteActive)) continue;
  2670.  
  2671.         if (displayIt) {
  2672.  
  2673.             if (!hilite)
  2674.                 CTEActivate(true, te);
  2675.             else
  2676.                 CTEActivate(false, te);
  2677.  
  2678.             for (scrollNum = 0; scrollNum < 2; ++scrollNum) {
  2679.                 scrollCtl = CTEScrollFromTE(te, scrollNum);
  2680.                 if (scrollCtl)
  2681.                     HiliteControl(scrollCtl, hilite);
  2682.             }
  2683.         }
  2684.  
  2685.         if (hilite)
  2686.             te = nil;
  2687.  
  2688.         return(te);
  2689.     }
  2690.  
  2691.     return(nil);
  2692. }
  2693.  
  2694.  
  2695.  
  2696. static TEHandle    dummyCTEWindActivate(WindowPtr window, Boolean displayIt)
  2697. {
  2698. #ifndef __MWERKS__
  2699. #pragma unused (window, displayIt)
  2700. #endif
  2701.  
  2702.     return(nil);
  2703. }
  2704.  
  2705.  
  2706.  
  2707. /*****************************************************************************/
  2708.  
  2709.  
  2710.  
  2711. /* This function is called after an edit to make sure that there is no extra
  2712. ** white space at the bottom of the viewRect.  If there are blank lines at
  2713. ** the bottom of the viewRect, and there is text scrolled off the top of the
  2714. ** viewRect, then the TextEdit control is scrolled to fill this space, or as
  2715. ** much of it as possible. */
  2716.  
  2717. #pragma segment TextEditControl
  2718. void    CTEAdjustTEBottom(TEHandle teHndl)
  2719. {
  2720.     Rect    destRct, viewRct;
  2721.     short    botDiff, topDiff;
  2722.  
  2723.     destRct = (*teHndl)->destRect;
  2724.     viewRct = (*teHndl)->viewRect;
  2725.     destRct.bottom = destRct.top + CTEDocHeight(teHndl);
  2726.  
  2727.     botDiff = viewRct.bottom - destRct.bottom;
  2728.  
  2729.     if (botDiff > 0) {
  2730.         topDiff = viewRct.top - destRct.top;
  2731.         if (botDiff > topDiff)
  2732.             botDiff = topDiff;
  2733.         if (botDiff)
  2734.             TEScroll(0, botDiff, teHndl);
  2735.     }
  2736. }
  2737.  
  2738.  
  2739.  
  2740. /*****************************************************************************/
  2741.  
  2742.  
  2743.  
  2744. /* Bring the scrollbar values up to date with the current document position
  2745. ** and length. */
  2746.  
  2747. #pragma segment TextEditControl
  2748. void    CTEAdjustScrollValues(TEHandle teHndl)
  2749. {
  2750.     short            scrollNum;
  2751.     ControlHandle    scrollCtl;
  2752.  
  2753.     for (scrollNum = 0; scrollNum < 2; ++scrollNum) {
  2754.         scrollCtl = CTEScrollFromTE(teHndl, scrollNum);
  2755.         if (scrollCtl)
  2756.             AdjustOneScrollValue(teHndl, scrollCtl, scrollNum);
  2757.     }
  2758. }
  2759.  
  2760.  
  2761.  
  2762. /*****************************************************************************/
  2763.  
  2764.  
  2765.  
  2766. #pragma segment TextEditControl
  2767. StScrpHandle    CTEGetFullStylScrap(TEHandle teHndl)
  2768. {
  2769.     short            selStart, selEnd;
  2770.     StScrpHandle    styl;
  2771.  
  2772.     selStart = (*teHndl)->selStart;
  2773.     selEnd   = (*teHndl)->selEnd;
  2774.  
  2775.     (*teHndl)->selStart = 0;
  2776.     (*teHndl)->selEnd   = (*teHndl)->teLength;
  2777.  
  2778.     styl = TEGetStyleScrapHandle(teHndl);
  2779.  
  2780.     (*teHndl)->selStart = selStart;
  2781.     (*teHndl)->selEnd   = selEnd;
  2782.  
  2783.     return(styl);
  2784. }
  2785.  
  2786.  
  2787.  
  2788. /*****************************************************************************/
  2789.  
  2790.  
  2791.  
  2792. #pragma segment TextEditControl
  2793. void    CTESetStylScrap(short begRng, short endRng, StScrpHandle styles, TEHandle teHndl)
  2794. {
  2795.     short            n, i, b, e, selStart, selEnd;
  2796.     ScrpSTElement    styl, s;
  2797.     TextStyle        srun;
  2798.     TEStyleHandle    shndl;
  2799.  
  2800.     if (!styles) return;
  2801.  
  2802.     shndl = TEGetStyleHandle(teHndl);
  2803.  
  2804.     selStart = (*teHndl)->selStart;
  2805.     selEnd   = (*teHndl)->selEnd;
  2806.  
  2807.     n = (*styles)->scrpNStyles;
  2808.  
  2809.     for (i = 0; i < n;) {
  2810.         styl = (*styles)->scrpStyleTab[i++];
  2811.         b  = styl.scrpStartChar;
  2812.         if (i == n)
  2813.             e = endRng;
  2814.         else {
  2815.             s = (*styles)->scrpStyleTab[i];
  2816.             e = s.scrpStartChar;
  2817.         }
  2818.         if (b >= endRng) break;            /* We're past the range for style application. */
  2819.         if (e <= begRng) continue;        /* We're not to the range for style application. */
  2820.  
  2821.         if (b < begRng) b = begRng;        /* Clip to range for style application. */
  2822.         if (e > endRng) e = endRng;
  2823.  
  2824.         if (b < e) {
  2825.             srun.tsFont  = styl.scrpFont;
  2826.             srun.tsFace  = styl.scrpFace;
  2827.             srun.tsSize  = styl.scrpSize;
  2828.             srun.tsColor = styl.scrpColor;
  2829.             (*teHndl)->selStart = b;
  2830.             (*teHndl)->selEnd   = e;
  2831.             TESetStyle(doAll, &srun, false, teHndl);
  2832.             TECalText(teHndl);
  2833.         }
  2834.     }
  2835.  
  2836.     (*teHndl)->selStart = selStart;
  2837.     (*teHndl)->selEnd   = selEnd;
  2838. }
  2839.  
  2840.  
  2841.  
  2842. /*****************************************************************************/
  2843.  
  2844.  
  2845.  
  2846. #pragma segment TextEditControl
  2847. short    CTEGetLineNum(TEHandle te, short offset)
  2848. {
  2849.     short    i;
  2850.  
  2851.     for (i = 0; i < (*te)->nLines; ++i)
  2852.         if ((*te)->lineStarts[i] > offset)
  2853.             break;
  2854.  
  2855.     return(i);
  2856. }
  2857.  
  2858.  
  2859.  
  2860. /*****************************************************************************/
  2861.  
  2862.  
  2863.  
  2864. #pragma segment TextEditControl
  2865. short    CTEGetLineHeight(TEHandle te, short lineNum, short *ascent)
  2866. {
  2867.     TEStyleHandle    tes;
  2868.     LHHandle        lhh;
  2869.  
  2870.     tes = *(TEStyleHandle *)&((*te)->txFont);
  2871.     lhh = (*tes)->lhTab;
  2872.  
  2873.     if (ascent) *ascent = (*lhh)[lineNum - 1].lhAscent;
  2874.     return((*lhh)[--lineNum].lhHeight);
  2875. }
  2876.  
  2877.  
  2878.  
  2879. /*****************************************************************************/
  2880.  
  2881.  
  2882.  
  2883. #pragma segment TextEditControl
  2884. void    CTEGetPStr(ControlHandle ctl, StringPtr pstr)
  2885. {
  2886.     TEHandle        te;
  2887.     unsigned short    len;
  2888.  
  2889.     if (!ctl) return;
  2890.     te = (TEHandle)GetControlReference(ctl);
  2891.     if (!te) return;
  2892.  
  2893.     len = (*te)->teLength;
  2894.     if (len > 255) len = 255;
  2895.  
  2896.     BlockMove(*(*te)->hText, pstr + 1, *pstr = len);
  2897. }
  2898.  
  2899.  
  2900.  
  2901. /*****************************************************************************/
  2902.  
  2903.  
  2904.  
  2905. #pragma segment TextEditControl
  2906. void    CTESetPStr(ControlHandle ctl, StringPtr pstr)
  2907. {
  2908.     TEHandle    te;
  2909.     Handle        h;
  2910.  
  2911.     if (!ctl) return;
  2912.     te = (TEHandle)GetControlReference(ctl);
  2913.     if (!te) return;
  2914.  
  2915.     h = NewHandle(pstr[0]);
  2916.     if (h) {
  2917.         BlockMove(pstr + 1, *h, pstr[0]);
  2918.         DisposeHandle(CTESwapText(te, h, nil, true));
  2919.     }
  2920. }
  2921.  
  2922.  
  2923.  
  2924. /*****************************************************************************/
  2925. /*****************************************************************************/
  2926.  
  2927.  
  2928.  
  2929. #pragma segment TextEditControl
  2930. static pascal void    VActionProc(ControlHandle scrollCtl, short part)
  2931. {
  2932.     short        delta, value, teOffset;
  2933.     short        oldValue, max, lh, as;
  2934.     TEHandle    te;
  2935.     TextStyle    styl;
  2936.     
  2937.     if (part) {                        /* If it was actually in the control. */
  2938.  
  2939.         te = gActiveTEHndl;
  2940.         TEGetStyle((*te)->selStart, &styl, &lh, &as, te);
  2941.         switch (part) {
  2942.             case inUpButton:
  2943.             case inDownButton:        /* One line. */
  2944.                 delta = lh;
  2945.                 break;
  2946.             case inPageUp:            /* One page. */
  2947.             case inPageDown:
  2948.                 delta = (*te)->viewRect.bottom - (*te)->viewRect.top;
  2949.                 if (delta > lh)
  2950.                     delta -= lh;
  2951.                 break;
  2952.         }
  2953.         if ( (part == inUpButton) || (part == inPageUp) )
  2954.             delta = -delta;        /* Reverse direction for an upper. */
  2955.  
  2956.         value = (oldValue = GetControlValue(scrollCtl)) + delta;
  2957.         if (value < 0)
  2958.             value = 0;
  2959.         if (value > (max = GetControlMaximum(scrollCtl)))
  2960.             value = max;
  2961.  
  2962.         if (value != oldValue) {
  2963.             SetControlValue(scrollCtl, value);
  2964.             teOffset = (*te)->viewRect.top - (*te)->destRect.top;
  2965.             if (value -= teOffset)
  2966.                 TEScroll(0, -value, te);
  2967.         }
  2968.     }
  2969. }
  2970.  
  2971.  
  2972.  
  2973. /*****************************************************************************/
  2974.  
  2975.  
  2976.  
  2977. #pragma segment TextEditControl
  2978. static pascal void    HActionProc(ControlHandle scrollCtl, short part)
  2979. {
  2980.     short        delta, value, teOffset;
  2981.     short        oldValue, max;
  2982.     TEHandle    te;
  2983.     
  2984.     if (part) {                        /* If it was actually in the control. */
  2985.  
  2986.         te = gActiveTEHndl;
  2987.         switch (part) {
  2988.             case inUpButton:
  2989.             case inDownButton:        /* One line. */
  2990.                 delta = 16;
  2991.                 break;
  2992.             case inPageUp:            /* One page. */
  2993.             case inPageDown:
  2994.                 delta = (*te)->viewRect.right - (*te)->viewRect.left;
  2995.                 if (delta > 16)
  2996.                     delta -= 16;
  2997.                 break;
  2998.         }
  2999.         if ( (part == inUpButton) || (part == inPageUp) )
  3000.             delta = -delta;        /* Reverse direction for an upper. */
  3001.  
  3002.         value = (oldValue = GetControlValue(scrollCtl)) + delta;
  3003.         if (value < 0)
  3004.             value = 0;
  3005.         if (value > (max = GetControlMaximum(scrollCtl)))
  3006.             value = max;
  3007.  
  3008.         if (value != oldValue) {
  3009.             SetControlValue(scrollCtl, value);
  3010.             teOffset = (*te)->viewRect.left - (*te)->destRect.left;
  3011.             if (value -= teOffset)
  3012.                 TEScroll(-value, 0, te);
  3013.         }
  3014.     }
  3015. }
  3016.  
  3017.  
  3018.  
  3019. /*****************************************************************************/
  3020.  
  3021.  
  3022.  
  3023. /* Bring one scrollbar value up to date with the current document position
  3024. ** and length. */
  3025.  
  3026. #pragma segment TextEditControl
  3027. static void    AdjustOneScrollValue(TEHandle teHndl, ControlHandle ctl, Boolean vert)
  3028. {
  3029.     Boolean    front;
  3030.     short    textPix, viewPix;
  3031.     short    max, oldMax, value, oldValue;
  3032.  
  3033.     front = ((WindowPeek)(*ctl)->contrlOwner)->hilited;
  3034.  
  3035.     oldValue = GetControlValue(ctl);
  3036.     oldMax   = GetControlMaximum(ctl);
  3037.  
  3038.     if (vert) {
  3039.         textPix = CTEDocHeight(teHndl);
  3040.         viewPix = (*teHndl)->viewRect.bottom - (*teHndl)->viewRect.top;
  3041.     }
  3042.     else {
  3043.         textPix = (*teHndl)->destRect.right - (*teHndl)->destRect.left;
  3044.         viewPix = (*teHndl)->viewRect.right - (*teHndl)->viewRect.left;
  3045.     }
  3046.     max = textPix - viewPix;
  3047.  
  3048.     if (max < 0)
  3049.         max = 0;
  3050.     if (max != oldMax) {
  3051.         if (front)
  3052.             SetControlMaximum(ctl, max);
  3053.         else
  3054.             (*ctl)->contrlMax = max;
  3055.     }
  3056.  
  3057.     if (vert)
  3058.         value = (*teHndl)->viewRect.top  - (*teHndl)->destRect.top;
  3059.     else
  3060.         value = (*teHndl)->viewRect.left - (*teHndl)->destRect.left;
  3061.  
  3062.     if (value < 0)
  3063.         value = 0;
  3064.     if (value > max)
  3065.         value = max;
  3066.     if (value != oldValue) {
  3067.         if (front)
  3068.             SetControlValue(ctl, value);
  3069.         else
  3070.             (*ctl)->contrlValue = value;
  3071.     }
  3072. }
  3073.  
  3074.  
  3075.  
  3076. /*****************************************************************************/
  3077.  
  3078.  
  3079.  
  3080. #pragma segment TextEditControl
  3081. Boolean    CTEUseTSMTE(void)
  3082. {
  3083.     return(gUseTSMTE = TSMTEAvailable());
  3084. }
  3085.  
  3086.  
  3087.  
  3088. /*****************************************************************************/
  3089.  
  3090.  
  3091.  
  3092. #pragma segment TextEditControl
  3093. Boolean    TSMTEAvailable(void)
  3094. {
  3095.     long    response;
  3096.     
  3097.     if (Gestalt(kTSMTESignature, &response)) return(false);
  3098.  
  3099.     return((response & (1 << gestaltTSMTE)) != 0);
  3100. }
  3101.  
  3102.  
  3103.  
  3104. /*****************************************************************************/
  3105.  
  3106.  
  3107.  
  3108. #pragma segment TextEditControl
  3109. static pascal void        TSMTEUpdateProc(TEHandle te, long fixLen, long inputAreaStart,
  3110.                                         long inputAreaEnd, long pinStart, long pinEnd, long refCon)
  3111. {
  3112. #ifndef __MWERKS__
  3113. #pragma unused (fixLen, inputAreaStart, inputAreaEnd, pinStart, pinEnd, refCon)
  3114. #endif
  3115.  
  3116.     CTEAdjustTEBottom(te);
  3117.     CTEAdjustScrollValues(te);
  3118. }
  3119.  
  3120.  
  3121.  
  3122. /*****************************************************************************/
  3123.  
  3124.  
  3125.  
  3126. /* PPCClikLoop gets called by the TextEdit Manager from TEClick.
  3127. ** It calls the old, default click loop routine that scrolls the
  3128. ** text, and then calls our own Pascal routine that handles
  3129. ** tracking the scroll bars to follow along.  It does the same thing as the
  3130. ** 68K asm routine ASMTECLIKLOOP, but for PowerPC we don't have all the
  3131. ** register concerns. */
  3132.  
  3133. #ifdef __powerc
  3134. static pascal Boolean    PPCClikLoop(TEPtr pTE)
  3135. {
  3136.     CallTEClickLoopProc(gDefaultClikLoopUPP, pTE);
  3137.         /* First call TextEdit's default ClikLoop routine */
  3138.  
  3139.     CTEClikLoop();        /* Now call our custom routine */
  3140.     return(true);
  3141. }
  3142.  
  3143. /*****/
  3144.  
  3145. /* PPCNoCaret does the samething as the 68K asm routine ASMNOCARET. Namely -- nothing. */
  3146. static pascal void    PPCNoCaret(const Rect *r, TEPtr pTE)
  3147. {
  3148. #ifndef __MWERKS__
  3149. #pragma unused (boundsRect, pTE)
  3150. #endif
  3151.     return;
  3152. }
  3153. #endif
  3154.  
  3155.  
  3156.